From patchwork Mon Nov 9 06:48:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 541610 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id DAF801402C2 for ; Mon, 9 Nov 2015 17:56:11 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b=GwUehJlE; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 37BE74BD4D; Mon, 9 Nov 2015 07:56:08 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EiXXk6TPT8Jh; Mon, 9 Nov 2015 07:56:08 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E71514BD4E; Mon, 9 Nov 2015 07:56:02 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9CEA44BCBF for ; Mon, 9 Nov 2015 07:55:57 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LjmMoDD1QojI for ; Mon, 9 Nov 2015 07:55:57 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-oi0-f50.google.com (mail-oi0-f50.google.com [209.85.218.50]) by theia.denx.de (Postfix) with ESMTPS id 18DAC4BB93 for ; Mon, 9 Nov 2015 07:55:54 +0100 (CET) Received: by oies6 with SMTP id s6so52218521oie.1 for ; Sun, 08 Nov 2015 22:55:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=+fK/OaLx7JaW2/zcjJWEIPKBOaA2y2wSLPD16DBREKY=; b=GwUehJlEg7aW9NBioazMDn5Jfnm93MynWbJ8ksfNdULRcFP2DGSTmG79eCa3gv/2cu Q8Ryzz4e9enV1XWgQdPdMDq9AhQP+HMxQnCA8nY1sivPS/aYtaWExw1aecd5bD5pyEEG p3iGera9QbRCLAW5hEatAbUEDNyGM1I01GI0oOXhYIEmlb4k1XOfrulPlGxTeGMuGWgm zPB5h3Rf9/fmTugJCcS3ChHBMmz5fg9EpUEy6UdUS/O51EyWdvO+CpmPyYDKe8UkBmgb onju/Y+TgkzmEui/ONujHRnPw1MTvrRszKKdj8WEKcBmLFNDDLbMA2vrm8d+h5UXX9r/ 1KMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=+fK/OaLx7JaW2/zcjJWEIPKBOaA2y2wSLPD16DBREKY=; b=axdKjzak40F518Tydwf/7pThQG9NgAs9vcHvy8GRhk08V2f0a8ZSIvXfBBX1l9puN6 SpwCny8sJHymW593A9+qEg1iLTENvZeXCC+tKQ9rNvqF7+eLS3x1u/D+K+AKjX/XxGxl 6pPJmZzsDc+sEgmx5RZYHhm8gg8lZPPkk7paVss4D3G3FGkU1p5JUKOrO5jA7Zb7aqxb PDpUqWB7okegBfKQtJuzfUI+5d2yjGYoP2cBt69rujFM5V8rPvwqCatCvF0uGUiB9AZN 9zzb8e1Hi8B9i5VBRe1TXxVNtWoNGoYil06OaywuKyKlVkAUJyjh7i5SfrdDyfLDCtjS BQRw== X-Gm-Message-State: ALoCoQniBVjLr8jOlhN1294USUvJrB+SRbs0R01I73QYmwedij+acE/R/mxSljmVTJwcCxPMBfzl X-Received: by 10.202.96.196 with SMTP id u187mr14869739oib.95.1447052152869; Sun, 08 Nov 2015 22:55:52 -0800 (PST) Received: from kaki.bld.corp.google.com ([2620:0:1005:1100:1dab:6a43:77d2:b718]) by smtp.gmail.com with ESMTPSA id r205sm4253196oih.6.2015.11.08.22.55.49 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Nov 2015 22:55:50 -0800 (PST) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 782E8223330; Sun, 8 Nov 2015 23:48:26 -0700 (MST) From: Simon Glass To: U-Boot Mailing List Date: Sun, 8 Nov 2015 23:48:06 -0700 Message-Id: <1447051688-24936-25-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.6.0.rc2.230.g3dd15c0 In-Reply-To: <1447051688-24936-1-git-send-email-sjg@chromium.org> References: <1447051688-24936-1-git-send-email-sjg@chromium.org> Cc: Marek Vasut Subject: [U-Boot] [PATCH v2 24/26] usb: sandbox: Add a USB emulation driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add a simple USB keyboard driver for sandbox. It provides a function to 'load' it with input data, which it will then stream through to the normal U-Boot input subsystem. When the input data is exhausted, the keyboard stops providing data. Signed-off-by: Simon Glass --- Changes in v2: None arch/sandbox/include/asm/test.h | 2 + drivers/usb/emul/Makefile | 1 + drivers/usb/emul/sandbox_keyb.c | 241 ++++++++++++++++++++++++++++++++++++++++ include/linux/usb/ch9.h | 20 ++++ 4 files changed, 264 insertions(+) create mode 100644 drivers/usb/emul/sandbox_keyb.c diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index d3c7851..224b0eb 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -86,4 +86,6 @@ long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time, */ long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time); +int sandbox_usb_keyb_add_string(struct udevice *dev, const char *str); + #endif diff --git a/drivers/usb/emul/Makefile b/drivers/usb/emul/Makefile index 8fd83d5..b64ac6d 100644 --- a/drivers/usb/emul/Makefile +++ b/drivers/usb/emul/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EMUL) += sandbox_flash.o obj-$(CONFIG_USB_EMUL) += sandbox_hub.o +obj-$(CONFIG_USB_EMUL) += sandbox_keyb.o obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o diff --git a/drivers/usb/emul/sandbox_keyb.c b/drivers/usb/emul/sandbox_keyb.c new file mode 100644 index 0000000..2735985 --- /dev/null +++ b/drivers/usb/emul/sandbox_keyb.c @@ -0,0 +1,241 @@ +/* + * (C) Copyright 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This driver emulates a USB keyboard using the USB HID specification (boot + * protocol) + */ + +enum { + SANDBOX_KEYB_EP_IN = 1, /* endpoints */ +}; + +enum cmd_phase { + PHASE_START, + PHASE_DATA, + PHASE_STATUS, +}; + +enum { + STRINGID_MANUFACTURER = 1, + STRINGID_PRODUCT, + STRINGID_SERIAL, + + STRINGID_COUNT, +}; + +/** + * struct sandbox_keyb_priv - private state for this driver + * + */ +struct sandbox_keyb_priv { + struct membuff in; +}; + +struct sandbox_keyb_plat { + struct usb_string keyb_strings[STRINGID_COUNT]; +}; + +static struct usb_device_descriptor keyb_device_desc = { + .bLength = sizeof(keyb_device_desc), + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16(0x0100), + + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + + .idVendor = __constant_cpu_to_le16(0x1234), + .idProduct = __constant_cpu_to_le16(0x5679), + .iManufacturer = STRINGID_MANUFACTURER, + .iProduct = STRINGID_PRODUCT, + .iSerialNumber = STRINGID_SERIAL, + .bNumConfigurations = 1, +}; + +static struct usb_config_descriptor keyb_config0 = { + .bLength = sizeof(keyb_config0), + .bDescriptorType = USB_DT_CONFIG, + + /* wTotalLength is set up by usb-emul-uclass */ + .bNumInterfaces = 2, + .bConfigurationValue = 0, + .iConfiguration = 0, + .bmAttributes = 1 << 7 | 1 << 5, + .bMaxPower = 50, +}; + +static struct usb_interface_descriptor keyb_interface0 = { + .bLength = sizeof(keyb_interface0), + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_SUB_HID_BOOT, + .bInterfaceProtocol = USB_PROT_HID_KEYBOARD, + .iInterface = 0, +}; + +static struct usb_class_hid_descriptor keyb_report0 = { + .bLength = sizeof(keyb_report0), + .bDescriptorType = USB_DT_HID, + .bcdCDC = 0x101, + .bCountryCode = 0, + .bNumDescriptors = 1, + .bDescriptorType0 = USB_DT_HID_REPORT, + .wDescriptorLength0 = 0x3f, +}; + +static struct usb_endpoint_descriptor keyb_endpoint0_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK, + .bmAttributes = USB_ENDPOINT_XFER_BULK | + USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16(8), + .bInterval = 0xa, +}; + +static struct usb_interface_descriptor keyb_interface1 = { + .bLength = sizeof(keyb_interface1), + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_SUB_HID_BOOT, + .bInterfaceProtocol = USB_PROT_HID_MOUSE, + .iInterface = 0, +}; + +static struct usb_class_hid_descriptor keyb_report1 = { + .bLength = sizeof(struct usb_class_hid_descriptor), + .bDescriptorType = USB_DT_HID, + .bcdCDC = 0x101, + .bCountryCode = 0, + .bNumDescriptors = 1, + .bDescriptorType0 = USB_DT_HID_REPORT, + .wDescriptorLength0 = 0x32, +}; + +static struct usb_endpoint_descriptor keyb_endpoint1_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK, + .bmAttributes = USB_ENDPOINT_XFER_BULK | + USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16(8), + .bInterval = 0xa, +}; + +static void *keyb_desc_list[] = { + &keyb_device_desc, + &keyb_config0, + &keyb_interface0, + &keyb_report0, + &keyb_endpoint0_in, + &keyb_interface1, + &keyb_report1, + &keyb_endpoint1_in, + NULL, +}; + +int sandbox_usb_keyb_add_string(struct udevice *dev, const char *str) +{ + struct sandbox_keyb_priv *priv = dev_get_priv(dev); + int len, ret; + + len = strlen(str); + ret = membuff_put(&priv->in, str, len); + if (ret != len) + return -ENOSPC; + + return 0; +} + +static int sandbox_keyb_control(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buff, int len, + struct devrequest *setup) +{ + debug("pipe=%lx\n", pipe); + + return -EIO; +} + +static int sandbox_keyb_interrupt(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, int interval) +{ + struct sandbox_keyb_priv *priv = dev_get_priv(dev); + uint8_t *data = buffer; + int ch; + + memset(data, '\0', length); + ch = membuff_getbyte(&priv->in); + if (ch != -1) + data[2] = 4 + ch - 'a'; + + return 0; +} + +static int sandbox_keyb_bind(struct udevice *dev) +{ + struct sandbox_keyb_plat *plat = dev_get_platdata(dev); + struct usb_string *fs; + + fs = plat->keyb_strings; + fs[0].id = STRINGID_MANUFACTURER; + fs[0].s = "sandbox"; + fs[1].id = STRINGID_PRODUCT; + fs[1].s = "keyboard"; + fs[2].id = STRINGID_SERIAL; + fs[2].s = dev->name; + + return usb_emul_setup_device(dev, PACKET_SIZE_8, plat->keyb_strings, + keyb_desc_list); +} + +static int sandbox_keyb_probe(struct udevice *dev) +{ + struct sandbox_keyb_priv *priv = dev_get_priv(dev); + + return membuff_new(&priv->in, 256); +} + +static const struct dm_usb_ops sandbox_usb_keyb_ops = { + .control = sandbox_keyb_control, + .interrupt = sandbox_keyb_interrupt, +}; + +static const struct udevice_id sandbox_usb_keyb_ids[] = { + { .compatible = "sandbox,usb-keyb" }, + { } +}; + +U_BOOT_DRIVER(usb_sandbox_keyb) = { + .name = "usb_sandbox_keyb", + .id = UCLASS_USB_EMUL, + .of_match = sandbox_usb_keyb_ids, + .bind = sandbox_keyb_bind, + .probe = sandbox_keyb_probe, + .ops = &sandbox_usb_keyb_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_keyb_priv), + .platdata_auto_alloc_size = sizeof(struct sandbox_keyb_plat), +}; diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 822fca0..0ad4782 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -229,6 +229,8 @@ struct usb_ctrlrequest { #define USB_DT_PIPE_USAGE 0x24 /* From the USB 3.0 spec */ #define USB_DT_SS_ENDPOINT_COMP 0x30 +/* From HID 1.11 spec */ +#define USB_DT_HID_REPORT 0x22 /* Conventional codes for class-specific descriptors. The convention is * defined in the USB "Common Class" Spec (3.11). Individual class specs @@ -385,6 +387,24 @@ struct usb_generic_descriptor { __u8 bDescriptorType; }; +struct __packed usb_class_hid_descriptor { + u8 bLength; + u8 bDescriptorType; + u16 bcdCDC; + u8 bCountryCode; + u8 bNumDescriptors; /* 0x01 */ + u8 bDescriptorType0; + u16 wDescriptorLength0; + /* optional descriptors are not supported. */ +}; + +struct __packed usb_class_report_descriptor { + u8 bLength; /* dummy */ + u8 bDescriptorType; + u16 wLength; + u8 bData[0]; +}; + /* * Endpoints */