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