1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <log.h>
10#include <os.h>
11#include <scsi.h>
12#include <usb.h>
13
14/*
15 * This driver emulates a USB keyboard using the USB HID specification (boot
16 * protocol)
17 */
18
19enum {
20	SANDBOX_KEYB_EP_IN		= 1,	/* endpoints */
21};
22
23enum cmd_phase {
24	PHASE_START,
25	PHASE_DATA,
26	PHASE_STATUS,
27};
28
29enum {
30	STRINGID_MANUFACTURER = 1,
31	STRINGID_PRODUCT,
32	STRINGID_SERIAL,
33
34	STRINGID_COUNT,
35};
36
37/**
38 * struct sandbox_keyb_priv - private state for this driver
39 *
40 */
41struct sandbox_keyb_priv {
42	struct membuff in;
43};
44
45struct sandbox_keyb_plat {
46	struct usb_string keyb_strings[STRINGID_COUNT];
47};
48
49static struct usb_device_descriptor keyb_device_desc = {
50	.bLength =		sizeof(keyb_device_desc),
51	.bDescriptorType =	USB_DT_DEVICE,
52
53	.bcdUSB =		__constant_cpu_to_le16(0x0100),
54
55	.bDeviceClass =		0,
56	.bDeviceSubClass =	0,
57	.bDeviceProtocol =	0,
58
59	.idVendor =		__constant_cpu_to_le16(0x1234),
60	.idProduct =		__constant_cpu_to_le16(0x5679),
61	.iManufacturer =	STRINGID_MANUFACTURER,
62	.iProduct =		STRINGID_PRODUCT,
63	.iSerialNumber =	STRINGID_SERIAL,
64	.bNumConfigurations =	1,
65};
66
67static struct usb_config_descriptor keyb_config0 = {
68	.bLength		= sizeof(keyb_config0),
69	.bDescriptorType	= USB_DT_CONFIG,
70
71	/* wTotalLength is set up by usb-emul-uclass */
72	.bNumInterfaces		= 2,
73	.bConfigurationValue	= 0,
74	.iConfiguration		= 0,
75	.bmAttributes		= 1 << 7 | 1 << 5,
76	.bMaxPower		= 50,
77};
78
79static struct usb_interface_descriptor keyb_interface0 = {
80	.bLength		= sizeof(keyb_interface0),
81	.bDescriptorType	= USB_DT_INTERFACE,
82
83	.bInterfaceNumber	= 0,
84	.bAlternateSetting	= 0,
85	.bNumEndpoints		= 1,
86	.bInterfaceClass	= USB_CLASS_HID,
87	.bInterfaceSubClass	= USB_SUB_HID_BOOT,
88	.bInterfaceProtocol	= USB_PROT_HID_KEYBOARD,
89	.iInterface		= 0,
90};
91
92static struct usb_class_hid_descriptor keyb_report0 = {
93	.bLength		= sizeof(keyb_report0),
94	.bDescriptorType	= USB_DT_HID,
95	.bcdCDC			= 0x101,
96	.bCountryCode		= 0,
97	.bNumDescriptors	= 1,
98	.bDescriptorType0	= USB_DT_HID_REPORT,
99	.wDescriptorLength0	= 0x3f,
100};
101
102static struct usb_endpoint_descriptor keyb_endpoint0_in = {
103	.bLength		= USB_DT_ENDPOINT_SIZE,
104	.bDescriptorType	= USB_DT_ENDPOINT,
105
106	.bEndpointAddress	= SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK,
107	.bmAttributes		= USB_ENDPOINT_XFER_BULK |
108					USB_ENDPOINT_XFER_ISOC,
109	.wMaxPacketSize		= __constant_cpu_to_le16(8),
110	.bInterval		= 0xa,
111};
112
113static struct usb_interface_descriptor keyb_interface1 = {
114	.bLength		= sizeof(keyb_interface1),
115	.bDescriptorType	= USB_DT_INTERFACE,
116
117	.bInterfaceNumber	= 1,
118	.bAlternateSetting	= 0,
119	.bNumEndpoints		= 1,
120	.bInterfaceClass	= USB_CLASS_HID,
121	.bInterfaceSubClass	= USB_SUB_HID_BOOT,
122	.bInterfaceProtocol	= USB_PROT_HID_MOUSE,
123	.iInterface		= 0,
124};
125
126static struct usb_class_hid_descriptor keyb_report1 = {
127	.bLength		= sizeof(struct usb_class_hid_descriptor),
128	.bDescriptorType	= USB_DT_HID,
129	.bcdCDC			= 0x101,
130	.bCountryCode		= 0,
131	.bNumDescriptors	= 1,
132	.bDescriptorType0	= USB_DT_HID_REPORT,
133	.wDescriptorLength0	= 0x32,
134};
135
136static struct usb_endpoint_descriptor keyb_endpoint1_in = {
137	.bLength		= USB_DT_ENDPOINT_SIZE,
138	.bDescriptorType	= USB_DT_ENDPOINT,
139
140	.bEndpointAddress	= SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK,
141	.bmAttributes		= USB_ENDPOINT_XFER_BULK |
142					USB_ENDPOINT_XFER_ISOC,
143	.wMaxPacketSize		= __constant_cpu_to_le16(8),
144	.bInterval		= 0xa,
145};
146
147static void *keyb_desc_list[] = {
148	&keyb_device_desc,
149	&keyb_config0,
150	&keyb_interface0,
151	&keyb_report0,
152	&keyb_endpoint0_in,
153	&keyb_interface1,
154	&keyb_report1,
155	&keyb_endpoint1_in,
156	NULL,
157};
158
159/**
160 * sandbox_usb_keyb_add_string() - provide a USB scancode buffer
161 *
162 * @dev:	the keyboard emulation device
163 * @scancode:	scancode buffer with USB_KBD_BOOT_REPORT_SIZE bytes
164 */
165int sandbox_usb_keyb_add_string(struct udevice *dev,
166				const char scancode[USB_KBD_BOOT_REPORT_SIZE])
167{
168	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
169	int ret;
170
171	ret = membuff_put(&priv->in, scancode, USB_KBD_BOOT_REPORT_SIZE);
172	if (ret != USB_KBD_BOOT_REPORT_SIZE)
173		return -ENOSPC;
174
175	return 0;
176}
177
178static int sandbox_keyb_control(struct udevice *dev, struct usb_device *udev,
179				unsigned long pipe, void *buff, int len,
180				struct devrequest *setup)
181{
182	debug("pipe=%lx\n", pipe);
183
184	return -EIO;
185}
186
187static int sandbox_keyb_interrupt(struct udevice *dev, struct usb_device *udev,
188		unsigned long pipe, void *buffer, int length, int interval,
189		bool nonblock)
190{
191	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
192	uint8_t *data = buffer;
193
194	memset(data, '\0', length);
195	if (length < USB_KBD_BOOT_REPORT_SIZE)
196		return 0;
197
198	membuff_get(&priv->in, buffer, USB_KBD_BOOT_REPORT_SIZE);
199
200	return 0;
201}
202
203static int sandbox_keyb_bind(struct udevice *dev)
204{
205	struct sandbox_keyb_plat *plat = dev_get_plat(dev);
206	struct usb_string *fs;
207
208	fs = plat->keyb_strings;
209	fs[0].id = STRINGID_MANUFACTURER;
210	fs[0].s = "sandbox";
211	fs[1].id = STRINGID_PRODUCT;
212	fs[1].s = "keyboard";
213	fs[2].id = STRINGID_SERIAL;
214	fs[2].s = dev->name;
215
216	return usb_emul_setup_device(dev, plat->keyb_strings, keyb_desc_list);
217}
218
219static int sandbox_keyb_probe(struct udevice *dev)
220{
221	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
222
223	/* Provide an 80 character keyboard buffer */
224	return membuff_new(&priv->in, 80 * USB_KBD_BOOT_REPORT_SIZE);
225}
226
227static const struct dm_usb_ops sandbox_usb_keyb_ops = {
228	.control	= sandbox_keyb_control,
229	.interrupt	= sandbox_keyb_interrupt,
230};
231
232static const struct udevice_id sandbox_usb_keyb_ids[] = {
233	{ .compatible = "sandbox,usb-keyb" },
234	{ }
235};
236
237U_BOOT_DRIVER(usb_sandbox_keyb) = {
238	.name	= "usb_sandbox_keyb",
239	.id	= UCLASS_USB_EMUL,
240	.of_match = sandbox_usb_keyb_ids,
241	.bind	= sandbox_keyb_bind,
242	.probe	= sandbox_keyb_probe,
243	.ops	= &sandbox_usb_keyb_ops,
244	.priv_auto	= sizeof(struct sandbox_keyb_priv),
245	.plat_auto	= sizeof(struct sandbox_keyb_plat),
246};
247