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
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 /**
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 */
sandbox_usb_keyb_add_string(struct udevice * dev,const char scancode[USB_KBD_BOOT_REPORT_SIZE])165 int 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
sandbox_keyb_control(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buff,int len,struct devrequest * setup)178 static 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
sandbox_keyb_interrupt(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buffer,int length,int interval,bool nonblock)187 static 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
sandbox_keyb_bind(struct udevice * dev)203 static 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
sandbox_keyb_probe(struct udevice * dev)219 static 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
227 static const struct dm_usb_ops sandbox_usb_keyb_ops = {
228 .control = sandbox_keyb_control,
229 .interrupt = sandbox_keyb_interrupt,
230 };
231
232 static const struct udevice_id sandbox_usb_keyb_ids[] = {
233 { .compatible = "sandbox,usb-keyb" },
234 { }
235 };
236
237 U_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