blob: 5ec1e98e4ed42da28b840779462a4403a7516c49 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassbe4ebd12015-11-08 23:48:06 -07002/*
3 * (C) Copyright 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassbe4ebd12015-11-08 23:48:06 -07005 */
6
7#include <common.h>
8#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Simon Glassbe4ebd12015-11-08 23:48:06 -070010#include <os.h>
11#include <scsi.h>
12#include <usb.h>
13
Simon Glassbe4ebd12015-11-08 23:48:06 -070014/*
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
Heinrich Schuchardt513255b2019-11-23 18:15:23 +0100159/**
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])
Simon Glassbe4ebd12015-11-08 23:48:06 -0700167{
168 struct sandbox_keyb_priv *priv = dev_get_priv(dev);
Heinrich Schuchardt513255b2019-11-23 18:15:23 +0100169 int ret;
Simon Glassbe4ebd12015-11-08 23:48:06 -0700170
Heinrich Schuchardt513255b2019-11-23 18:15:23 +0100171 ret = membuff_put(&priv->in, scancode, USB_KBD_BOOT_REPORT_SIZE);
172 if (ret != USB_KBD_BOOT_REPORT_SIZE)
Simon Glassbe4ebd12015-11-08 23:48:06 -0700173 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,
Michal Suchanek1c95b9f2019-08-18 10:55:27 +0200188 unsigned long pipe, void *buffer, int length, int interval,
189 bool nonblock)
Simon Glassbe4ebd12015-11-08 23:48:06 -0700190{
191 struct sandbox_keyb_priv *priv = dev_get_priv(dev);
192 uint8_t *data = buffer;
Simon Glassbe4ebd12015-11-08 23:48:06 -0700193
194 memset(data, '\0', length);
Heinrich Schuchardt513255b2019-11-23 18:15:23 +0100195 if (length < USB_KBD_BOOT_REPORT_SIZE)
196 return 0;
197
198 membuff_get(&priv->in, buffer, USB_KBD_BOOT_REPORT_SIZE);
Simon Glassbe4ebd12015-11-08 23:48:06 -0700199
200 return 0;
201}
202
203static int sandbox_keyb_bind(struct udevice *dev)
204{
Simon Glassfa20e932020-12-03 16:55:20 -0700205 struct sandbox_keyb_plat *plat = dev_get_plat(dev);
Simon Glassbe4ebd12015-11-08 23:48:06 -0700206 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
Bin Mengd502cf12017-10-01 06:19:36 -0700216 return usb_emul_setup_device(dev, plat->keyb_strings, keyb_desc_list);
Simon Glassbe4ebd12015-11-08 23:48:06 -0700217}
218
219static int sandbox_keyb_probe(struct udevice *dev)
220{
221 struct sandbox_keyb_priv *priv = dev_get_priv(dev);
222
Heinrich Schuchardt513255b2019-11-23 18:15:23 +0100223 /* Provide an 80 character keyboard buffer */
224 return membuff_new(&priv->in, 80 * USB_KBD_BOOT_REPORT_SIZE);
Simon Glassbe4ebd12015-11-08 23:48:06 -0700225}
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,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700244 .priv_auto = sizeof(struct sandbox_keyb_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -0700245 .plat_auto = sizeof(struct sandbox_keyb_plat),
Simon Glassbe4ebd12015-11-08 23:48:06 -0700246};