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