xref: /openbmc/u-boot/drivers/usb/emul/sandbox_keyb.c (revision d024236e5a31a2b4b82cbcc98b31b8170fc88d28)
1 /*
2  * (C) Copyright 2015 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <dm.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 
19 enum {
20 	SANDBOX_KEYB_EP_IN		= 1,	/* endpoints */
21 };
22 
23 enum cmd_phase {
24 	PHASE_START,
25 	PHASE_DATA,
26 	PHASE_STATUS,
27 };
28 
29 enum {
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  */
41 struct sandbox_keyb_priv {
42 	struct membuff in;
43 };
44 
45 struct sandbox_keyb_plat {
46 	struct usb_string keyb_strings[STRINGID_COUNT];
47 };
48 
49 static 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 
67 static 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 
79 static 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 
92 static 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 
102 static 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 
113 static 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 
126 static 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 
136 static 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 
147 static 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 int sandbox_usb_keyb_add_string(struct udevice *dev, const char *str)
160 {
161 	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
162 	int len, ret;
163 
164 	len = strlen(str);
165 	ret = membuff_put(&priv->in, str, len);
166 	if (ret != len)
167 		return -ENOSPC;
168 
169 	return 0;
170 }
171 
172 static int sandbox_keyb_control(struct udevice *dev, struct usb_device *udev,
173 				unsigned long pipe, void *buff, int len,
174 				struct devrequest *setup)
175 {
176 	debug("pipe=%lx\n", pipe);
177 
178 	return -EIO;
179 }
180 
181 static int sandbox_keyb_interrupt(struct udevice *dev, struct usb_device *udev,
182 		unsigned long pipe, void *buffer, int length, int interval)
183 {
184 	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
185 	uint8_t *data = buffer;
186 	int ch;
187 
188 	memset(data, '\0', length);
189 	ch = membuff_getbyte(&priv->in);
190 	if (ch != -1)
191 		data[2] = 4 + ch - 'a';
192 
193 	return 0;
194 }
195 
196 static int sandbox_keyb_bind(struct udevice *dev)
197 {
198 	struct sandbox_keyb_plat *plat = dev_get_platdata(dev);
199 	struct usb_string *fs;
200 
201 	fs = plat->keyb_strings;
202 	fs[0].id = STRINGID_MANUFACTURER;
203 	fs[0].s = "sandbox";
204 	fs[1].id = STRINGID_PRODUCT;
205 	fs[1].s = "keyboard";
206 	fs[2].id = STRINGID_SERIAL;
207 	fs[2].s = dev->name;
208 
209 	return usb_emul_setup_device(dev, plat->keyb_strings, keyb_desc_list);
210 }
211 
212 static int sandbox_keyb_probe(struct udevice *dev)
213 {
214 	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
215 
216 	return membuff_new(&priv->in, 256);
217 }
218 
219 static const struct dm_usb_ops sandbox_usb_keyb_ops = {
220 	.control	= sandbox_keyb_control,
221 	.interrupt	= sandbox_keyb_interrupt,
222 };
223 
224 static const struct udevice_id sandbox_usb_keyb_ids[] = {
225 	{ .compatible = "sandbox,usb-keyb" },
226 	{ }
227 };
228 
229 U_BOOT_DRIVER(usb_sandbox_keyb) = {
230 	.name	= "usb_sandbox_keyb",
231 	.id	= UCLASS_USB_EMUL,
232 	.of_match = sandbox_usb_keyb_ids,
233 	.bind	= sandbox_keyb_bind,
234 	.probe	= sandbox_keyb_probe,
235 	.ops	= &sandbox_usb_keyb_ops,
236 	.priv_auto_alloc_size = sizeof(struct sandbox_keyb_priv),
237 	.platdata_auto_alloc_size = sizeof(struct sandbox_keyb_plat),
238 };
239