18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/* Copyright (C) 2006-2017 Oracle Corporation */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/vbox_err.h>
58c2ecf20Sopenharmony_ci#include "vbox_drv.h"
68c2ecf20Sopenharmony_ci#include "vboxvideo_guest.h"
78c2ecf20Sopenharmony_ci#include "vboxvideo_vbe.h"
88c2ecf20Sopenharmony_ci#include "hgsmi_channels.h"
98c2ecf20Sopenharmony_ci#include "hgsmi_ch_setup.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/**
128c2ecf20Sopenharmony_ci * Inform the host of the location of the host flags in VRAM via an HGSMI cmd.
138c2ecf20Sopenharmony_ci * Return: 0 or negative errno value.
148c2ecf20Sopenharmony_ci * @ctx:        The context of the guest heap to use.
158c2ecf20Sopenharmony_ci * @location:   The offset chosen for the flags within guest VRAM.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ciint hgsmi_report_flags_location(struct gen_pool *ctx, u32 location)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct hgsmi_buffer_location *p;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_HGSMI,
228c2ecf20Sopenharmony_ci			       HGSMI_CC_HOST_FLAGS_LOCATION);
238c2ecf20Sopenharmony_ci	if (!p)
248c2ecf20Sopenharmony_ci		return -ENOMEM;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	p->buf_location = location;
278c2ecf20Sopenharmony_ci	p->buf_len = sizeof(struct hgsmi_host_flags);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	hgsmi_buffer_submit(ctx, p);
308c2ecf20Sopenharmony_ci	hgsmi_buffer_free(ctx, p);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return 0;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/**
368c2ecf20Sopenharmony_ci * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
378c2ecf20Sopenharmony_ci * Return: 0 or negative errno value.
388c2ecf20Sopenharmony_ci * @ctx:        The context of the guest heap to use.
398c2ecf20Sopenharmony_ci * @caps:       The capabilities to report, see vbva_caps.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ciint hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct vbva_caps *p;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);
468c2ecf20Sopenharmony_ci	if (!p)
478c2ecf20Sopenharmony_ci		return -ENOMEM;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	p->rc = VERR_NOT_IMPLEMENTED;
508c2ecf20Sopenharmony_ci	p->caps = caps;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	hgsmi_buffer_submit(ctx, p);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	WARN_ON_ONCE(p->rc < 0);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	hgsmi_buffer_free(ctx, p);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ciint hgsmi_test_query_conf(struct gen_pool *ctx)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	u32 value = 0;
648c2ecf20Sopenharmony_ci	int ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	ret = hgsmi_query_conf(ctx, U32_MAX, &value);
678c2ecf20Sopenharmony_ci	if (ret)
688c2ecf20Sopenharmony_ci		return ret;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return value == U32_MAX ? 0 : -EIO;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * Query the host for an HGSMI configuration parameter via an HGSMI command.
758c2ecf20Sopenharmony_ci * Return: 0 or negative errno value.
768c2ecf20Sopenharmony_ci * @ctx:        The context containing the heap used.
778c2ecf20Sopenharmony_ci * @index:      The index of the parameter to query.
788c2ecf20Sopenharmony_ci * @value_ret:  Where to store the value of the parameter on success.
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ciint hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct vbva_conf32 *p;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
858c2ecf20Sopenharmony_ci			       VBVA_QUERY_CONF32);
868c2ecf20Sopenharmony_ci	if (!p)
878c2ecf20Sopenharmony_ci		return -ENOMEM;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	p->index = index;
908c2ecf20Sopenharmony_ci	p->value = U32_MAX;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	hgsmi_buffer_submit(ctx, p);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	*value_ret = p->value;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	hgsmi_buffer_free(ctx, p);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/**
1028c2ecf20Sopenharmony_ci * Pass the host a new mouse pointer shape via an HGSMI command.
1038c2ecf20Sopenharmony_ci * Return: 0 or negative errno value.
1048c2ecf20Sopenharmony_ci * @ctx:        The context containing the heap to be used.
1058c2ecf20Sopenharmony_ci * @flags:      Cursor flags.
1068c2ecf20Sopenharmony_ci * @hot_x:      Horizontal position of the hot spot.
1078c2ecf20Sopenharmony_ci * @hot_y:      Vertical position of the hot spot.
1088c2ecf20Sopenharmony_ci * @width:      Width in pixels of the cursor.
1098c2ecf20Sopenharmony_ci * @height:     Height in pixels of the cursor.
1108c2ecf20Sopenharmony_ci * @pixels:     Pixel data, @see VMMDevReqMousePointer for the format.
1118c2ecf20Sopenharmony_ci * @len:        Size in bytes of the pixel data.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_ciint hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
1148c2ecf20Sopenharmony_ci			       u32 hot_x, u32 hot_y, u32 width, u32 height,
1158c2ecf20Sopenharmony_ci			       u8 *pixels, u32 len)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct vbva_mouse_pointer_shape *p;
1188c2ecf20Sopenharmony_ci	u32 pixel_len = 0;
1198c2ecf20Sopenharmony_ci	int rc;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (flags & VBOX_MOUSE_POINTER_SHAPE) {
1228c2ecf20Sopenharmony_ci		/*
1238c2ecf20Sopenharmony_ci		 * Size of the pointer data:
1248c2ecf20Sopenharmony_ci		 * sizeof (AND mask) + sizeof (XOR_MASK)
1258c2ecf20Sopenharmony_ci		 */
1268c2ecf20Sopenharmony_ci		pixel_len = ((((width + 7) / 8) * height + 3) & ~3) +
1278c2ecf20Sopenharmony_ci			 width * 4 * height;
1288c2ecf20Sopenharmony_ci		if (pixel_len > len)
1298c2ecf20Sopenharmony_ci			return -EINVAL;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		/*
1328c2ecf20Sopenharmony_ci		 * If shape is supplied, then always create the pointer visible.
1338c2ecf20Sopenharmony_ci		 * See comments in 'vboxUpdatePointerShape'
1348c2ecf20Sopenharmony_ci		 */
1358c2ecf20Sopenharmony_ci		flags |= VBOX_MOUSE_POINTER_VISIBLE;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA,
1398c2ecf20Sopenharmony_ci			       VBVA_MOUSE_POINTER_SHAPE);
1408c2ecf20Sopenharmony_ci	if (!p)
1418c2ecf20Sopenharmony_ci		return -ENOMEM;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	p->result = VINF_SUCCESS;
1448c2ecf20Sopenharmony_ci	p->flags = flags;
1458c2ecf20Sopenharmony_ci	p->hot_X = hot_x;
1468c2ecf20Sopenharmony_ci	p->hot_y = hot_y;
1478c2ecf20Sopenharmony_ci	p->width = width;
1488c2ecf20Sopenharmony_ci	p->height = height;
1498c2ecf20Sopenharmony_ci	if (pixel_len)
1508c2ecf20Sopenharmony_ci		memcpy(p->data, pixels, pixel_len);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	hgsmi_buffer_submit(ctx, p);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	switch (p->result) {
1558c2ecf20Sopenharmony_ci	case VINF_SUCCESS:
1568c2ecf20Sopenharmony_ci		rc = 0;
1578c2ecf20Sopenharmony_ci		break;
1588c2ecf20Sopenharmony_ci	case VERR_NO_MEMORY:
1598c2ecf20Sopenharmony_ci		rc = -ENOMEM;
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	case VERR_NOT_SUPPORTED:
1628c2ecf20Sopenharmony_ci		rc = -EBUSY;
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	default:
1658c2ecf20Sopenharmony_ci		rc = -EINVAL;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	hgsmi_buffer_free(ctx, p);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return rc;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/**
1748c2ecf20Sopenharmony_ci * Report the guest cursor position.  The host may wish to use this information
1758c2ecf20Sopenharmony_ci * to re-position its own cursor (though this is currently unlikely).  The
1768c2ecf20Sopenharmony_ci * current host cursor position is returned.
1778c2ecf20Sopenharmony_ci * Return: 0 or negative errno value.
1788c2ecf20Sopenharmony_ci * @ctx:              The context containing the heap used.
1798c2ecf20Sopenharmony_ci * @report_position:  Are we reporting a position?
1808c2ecf20Sopenharmony_ci * @x:                Guest cursor X position.
1818c2ecf20Sopenharmony_ci * @y:                Guest cursor Y position.
1828c2ecf20Sopenharmony_ci * @x_host:           Host cursor X position is stored here.  Optional.
1838c2ecf20Sopenharmony_ci * @y_host:           Host cursor Y position is stored here.  Optional.
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciint hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
1868c2ecf20Sopenharmony_ci			  u32 x, u32 y, u32 *x_host, u32 *y_host)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct vbva_cursor_position *p;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
1918c2ecf20Sopenharmony_ci			       VBVA_CURSOR_POSITION);
1928c2ecf20Sopenharmony_ci	if (!p)
1938c2ecf20Sopenharmony_ci		return -ENOMEM;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	p->report_position = report_position;
1968c2ecf20Sopenharmony_ci	p->x = x;
1978c2ecf20Sopenharmony_ci	p->y = y;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	hgsmi_buffer_submit(ctx, p);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	*x_host = p->x;
2028c2ecf20Sopenharmony_ci	*y_host = p->y;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	hgsmi_buffer_free(ctx, p);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return 0;
2078c2ecf20Sopenharmony_ci}
208