162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* Copyright (C) 2006-2017 Oracle Corporation */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/vbox_err.h> 562306a36Sopenharmony_ci#include "vbox_drv.h" 662306a36Sopenharmony_ci#include "vboxvideo_guest.h" 762306a36Sopenharmony_ci#include "vboxvideo_vbe.h" 862306a36Sopenharmony_ci#include "hgsmi_channels.h" 962306a36Sopenharmony_ci#include "hgsmi_ch_setup.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/** 1262306a36Sopenharmony_ci * hgsmi_report_flags_location - Inform the host of the location of 1362306a36Sopenharmony_ci * the host flags in VRAM via an HGSMI cmd. 1462306a36Sopenharmony_ci * Return: 0 or negative errno value. 1562306a36Sopenharmony_ci * @ctx: The context of the guest heap to use. 1662306a36Sopenharmony_ci * @location: The offset chosen for the flags within guest VRAM. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ciint hgsmi_report_flags_location(struct gen_pool *ctx, u32 location) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct hgsmi_buffer_location *p; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_HGSMI, 2362306a36Sopenharmony_ci HGSMI_CC_HOST_FLAGS_LOCATION); 2462306a36Sopenharmony_ci if (!p) 2562306a36Sopenharmony_ci return -ENOMEM; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci p->buf_location = location; 2862306a36Sopenharmony_ci p->buf_len = sizeof(struct hgsmi_host_flags); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci hgsmi_buffer_submit(ctx, p); 3162306a36Sopenharmony_ci hgsmi_buffer_free(ctx, p); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return 0; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/** 3762306a36Sopenharmony_ci * hgsmi_send_caps_info - Notify the host of HGSMI-related guest capabilities 3862306a36Sopenharmony_ci * via an HGSMI command. 3962306a36Sopenharmony_ci * Return: 0 or negative errno value. 4062306a36Sopenharmony_ci * @ctx: The context of the guest heap to use. 4162306a36Sopenharmony_ci * @caps: The capabilities to report, see vbva_caps. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ciint hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct vbva_caps *p; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS); 4862306a36Sopenharmony_ci if (!p) 4962306a36Sopenharmony_ci return -ENOMEM; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci p->rc = VERR_NOT_IMPLEMENTED; 5262306a36Sopenharmony_ci p->caps = caps; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci hgsmi_buffer_submit(ctx, p); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci WARN_ON_ONCE(p->rc < 0); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci hgsmi_buffer_free(ctx, p); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint hgsmi_test_query_conf(struct gen_pool *ctx) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci u32 value = 0; 6662306a36Sopenharmony_ci int ret; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ret = hgsmi_query_conf(ctx, U32_MAX, &value); 6962306a36Sopenharmony_ci if (ret) 7062306a36Sopenharmony_ci return ret; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return value == U32_MAX ? 0 : -EIO; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * hgsmi_query_conf - Query the host for an HGSMI configuration 7762306a36Sopenharmony_ci * parameter via an HGSMI command. 7862306a36Sopenharmony_ci * Return: 0 or negative errno value. 7962306a36Sopenharmony_ci * @ctx: The context containing the heap used. 8062306a36Sopenharmony_ci * @index: The index of the parameter to query. 8162306a36Sopenharmony_ci * @value_ret: Where to store the value of the parameter on success. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ciint hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct vbva_conf32 *p; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, 8862306a36Sopenharmony_ci VBVA_QUERY_CONF32); 8962306a36Sopenharmony_ci if (!p) 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci p->index = index; 9362306a36Sopenharmony_ci p->value = U32_MAX; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci hgsmi_buffer_submit(ctx, p); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci *value_ret = p->value; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci hgsmi_buffer_free(ctx, p); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * hgsmi_update_pointer_shape - Pass the host a new mouse pointer shape 10662306a36Sopenharmony_ci * via an HGSMI command. 10762306a36Sopenharmony_ci * Return: 0 or negative errno value. 10862306a36Sopenharmony_ci * @ctx: The context containing the heap to be used. 10962306a36Sopenharmony_ci * @flags: Cursor flags. 11062306a36Sopenharmony_ci * @hot_x: Horizontal position of the hot spot. 11162306a36Sopenharmony_ci * @hot_y: Vertical position of the hot spot. 11262306a36Sopenharmony_ci * @width: Width in pixels of the cursor. 11362306a36Sopenharmony_ci * @height: Height in pixels of the cursor. 11462306a36Sopenharmony_ci * @pixels: Pixel data, @see VMMDevReqMousePointer for the format. 11562306a36Sopenharmony_ci * @len: Size in bytes of the pixel data. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ciint hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags, 11862306a36Sopenharmony_ci u32 hot_x, u32 hot_y, u32 width, u32 height, 11962306a36Sopenharmony_ci u8 *pixels, u32 len) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct vbva_mouse_pointer_shape *p; 12262306a36Sopenharmony_ci u32 pixel_len = 0; 12362306a36Sopenharmony_ci int rc; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (flags & VBOX_MOUSE_POINTER_SHAPE) { 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Size of the pointer data: 12862306a36Sopenharmony_ci * sizeof (AND mask) + sizeof (XOR_MASK) 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci pixel_len = ((((width + 7) / 8) * height + 3) & ~3) + 13162306a36Sopenharmony_ci width * 4 * height; 13262306a36Sopenharmony_ci if (pixel_len > len) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* 13662306a36Sopenharmony_ci * If shape is supplied, then always create the pointer visible. 13762306a36Sopenharmony_ci * See comments in 'vboxUpdatePointerShape' 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci flags |= VBOX_MOUSE_POINTER_VISIBLE; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA, 14362306a36Sopenharmony_ci VBVA_MOUSE_POINTER_SHAPE); 14462306a36Sopenharmony_ci if (!p) 14562306a36Sopenharmony_ci return -ENOMEM; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci p->result = VINF_SUCCESS; 14862306a36Sopenharmony_ci p->flags = flags; 14962306a36Sopenharmony_ci p->hot_X = hot_x; 15062306a36Sopenharmony_ci p->hot_y = hot_y; 15162306a36Sopenharmony_ci p->width = width; 15262306a36Sopenharmony_ci p->height = height; 15362306a36Sopenharmony_ci if (pixel_len) 15462306a36Sopenharmony_ci memcpy(p->data, pixels, pixel_len); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci hgsmi_buffer_submit(ctx, p); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci switch (p->result) { 15962306a36Sopenharmony_ci case VINF_SUCCESS: 16062306a36Sopenharmony_ci rc = 0; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci case VERR_NO_MEMORY: 16362306a36Sopenharmony_ci rc = -ENOMEM; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case VERR_NOT_SUPPORTED: 16662306a36Sopenharmony_ci rc = -EBUSY; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci rc = -EINVAL; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci hgsmi_buffer_free(ctx, p); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return rc; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * hgsmi_cursor_position - Report the guest cursor position. The host may 17962306a36Sopenharmony_ci * wish to use this information to re-position its 18062306a36Sopenharmony_ci * own cursor (though this is currently unlikely). 18162306a36Sopenharmony_ci * The current host cursor position is returned. 18262306a36Sopenharmony_ci * Return: 0 or negative errno value. 18362306a36Sopenharmony_ci * @ctx: The context containing the heap used. 18462306a36Sopenharmony_ci * @report_position: Are we reporting a position? 18562306a36Sopenharmony_ci * @x: Guest cursor X position. 18662306a36Sopenharmony_ci * @y: Guest cursor Y position. 18762306a36Sopenharmony_ci * @x_host: Host cursor X position is stored here. Optional. 18862306a36Sopenharmony_ci * @y_host: Host cursor Y position is stored here. Optional. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ciint hgsmi_cursor_position(struct gen_pool *ctx, bool report_position, 19162306a36Sopenharmony_ci u32 x, u32 y, u32 *x_host, u32 *y_host) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct vbva_cursor_position *p; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, 19662306a36Sopenharmony_ci VBVA_CURSOR_POSITION); 19762306a36Sopenharmony_ci if (!p) 19862306a36Sopenharmony_ci return -ENOMEM; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci p->report_position = report_position; 20162306a36Sopenharmony_ci p->x = x; 20262306a36Sopenharmony_ci p->y = y; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci hgsmi_buffer_submit(ctx, p); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci *x_host = p->x; 20762306a36Sopenharmony_ci *y_host = p->y; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci hgsmi_buffer_free(ctx, p); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci} 213