/**************************************************************************** * drivers/usbdev/adb.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_BOARD_USBDEV_SERIALSTR #include #endif #include "usbdev_fs.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* FIXME use minor for char device npath */ #ifdef CONFIG_USBFASTBOOT # define USBADB_CHARDEV_PATH "/dev/fastboot" #else # define USBADB_CHARDEV_PATH "/dev/adb0" #endif /* USB Controller */ #ifdef CONFIG_USBDEV_SELFPOWERED # define USBADB_SELFPOWERED USB_CONFIG_ATTR_SELFPOWER #else # define USBADB_SELFPOWERED (0) #endif #ifdef CONFIG_USBDEV_REMOTEWAKEUP # define USBADB_REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP #else # define USBADB_REMOTEWAKEUP (0) #endif /* Buffer big enough for any of our descriptors (the config descriptor is the * biggest). */ #define USBADB_MXDESCLEN (64) #define USBADB_MAXSTRLEN (USBADB_MXDESCLEN-2) /* Device descriptor values */ #define USBADB_VERSIONNO (0x0101) /* Device version number 1.1 (BCD) */ /* String language */ #define USBADB_STR_LANGUAGE (0x0409) /* en-us */ /* Descriptor strings. If there serial device is part of a composite device * then the manufacturer, product, and serial number strings will be provided * by the composite logic. */ #ifndef CONFIG_USBADB_COMPOSITE # define USBADB_MANUFACTURERSTRID (1) # define USBADB_PRODUCTSTRID (2) # define USBADB_SERIALSTRID (3) # define USBADB_CONFIGSTRID (4) # define USBADB_INTERFACESTRID (5) # define USBADB_NSTRIDS (5) #else # define USBADB_INTERFACESTRID (1) # define USBADB_NSTRIDS (1) #endif #define USBADB_NCONFIGS (1) #ifdef CONFIG_USBFASTBOOT # define USBADB_INTERFACEPROTOCOL (3) #else # define USBADB_INTERFACEPROTOCOL (1) #endif /**************************************************************************** * Private Data ****************************************************************************/ /* USB descriptor ***********************************************************/ #ifndef CONFIG_USBADB_COMPOSITE static const struct usb_devdesc_s g_adb_devdesc = { .len = USB_SIZEOF_DEVDESC, /* Descriptor length */ .type = USB_DESC_TYPE_DEVICE, /* Descriptor type */ .usb = /* USB version */ { LSBYTE(0x0200), MSBYTE(0x0200) }, .classid = 0, /* Device class */ .subclass = 0, /* Device sub-class */ .protocol = 0, /* Device protocol */ .mxpacketsize = CONFIG_USBADB_EP0MAXPACKET, /* Max packet size (ep0) */ .vendor = /* Vendor ID */ { LSBYTE(CONFIG_USBADB_VENDORID), MSBYTE(CONFIG_USBADB_VENDORID) }, .product = /* Product ID */ { LSBYTE(CONFIG_USBADB_PRODUCTID), MSBYTE(CONFIG_USBADB_PRODUCTID) }, .device = /* Device ID */ { LSBYTE(USBADB_VERSIONNO), MSBYTE(USBADB_VERSIONNO) }, .imfgr = USBADB_MANUFACTURERSTRID, /* Manufacturer */ .iproduct = USBADB_PRODUCTSTRID, /* Product */ .serno = USBADB_SERIALSTRID, /* Serial number */ .nconfigs = USBADB_NCONFIGS, /* Number of configurations */ }; # ifdef CONFIG_USBDEV_DUALSPEED static const struct usb_qualdesc_s g_adb_qualdesc = { USB_SIZEOF_QUALDESC, /* len */ USB_DESC_TYPE_DEVICEQUALIFIER, /* type */ { /* usb */ LSBYTE(0x0200), MSBYTE(0x0200) }, 0, /* classid */ 0, /* subclass */ 0, /* protocol */ CONFIG_USBADB_EP0MAXPACKET, /* mxpacketsize */ USBADB_NCONFIGS, /* nconfigs */ 0, /* reserved */ }; # endif static const struct usbdev_strdesc_s g_adb_strdesc[] = { {USBADB_MANUFACTURERSTRID, CONFIG_USBADB_VENDORSTR}, {USBADB_PRODUCTSTRID, CONFIG_USBADB_PRODUCTSTR}, # ifdef CONFIG_USBADB_SERIALSTR {USBADB_SERIALSTRID, CONFIG_USBADB_SERIALSTR}, # else {USBADB_SERIALSTRID, ""}, # endif {USBADB_CONFIGSTRID, CONFIG_USBADB_CONFIGSTR}, {} }; static const struct usbdev_strdescs_s g_adb_strdescs = { .language = USBADB_STR_LANGUAGE, .strdesc = g_adb_strdesc, }; static const struct usb_cfgdesc_s g_adb_cfgdesc = { .len = USB_SIZEOF_CFGDESC, /* Descriptor length */ .type = USB_DESC_TYPE_CONFIG, /* Descriptor type */ .cfgvalue = 1, /* Configuration value */ .icfg = USBADB_CONFIGSTRID, /* Configuration */ .attr = USB_CONFIG_ATTR_ONE | USBADB_SELFPOWERED | USBADB_REMOTEWAKEUP, /* Attributes */ .mxpower = (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* Max power (mA/2) */ }; static const struct usbdev_devdescs_s g_adb_devdescs = { .cfgdesc = &g_adb_cfgdesc, .strdescs = &g_adb_strdescs, .devdesc = &g_adb_devdesc, #ifdef CONFIG_USBDEV_DUALSPEED .qualdesc = &g_adb_qualdesc, #endif }; #endif static const struct usb_ifdesc_s g_adb_ifdesc = { .len = USB_SIZEOF_IFDESC, .type = USB_DESC_TYPE_INTERFACE, .ifno = 0, .alt = 0, .neps = 2, .classid = USB_CLASS_VENDOR_SPEC, .subclass = 0x42, .protocol = USBADB_INTERFACEPROTOCOL, .iif = USBADB_INTERFACESTRID }; static const struct usbdev_epinfo_s g_adb_epbulkin = { .desc = { .len = USB_SIZEOF_EPDESC, .type = USB_DESC_TYPE_ENDPOINT, .addr = USB_DIR_IN, .attr = USB_EP_ATTR_XFER_BULK | USB_EP_ATTR_NO_SYNC | USB_EP_ATTR_USAGE_DATA, .interval = 0, }, .reqnum = CONFIG_USBADB_NWRREQS, .fssize = CONFIG_USBADB_EPBULKIN_FSSIZE, #ifdef CONFIG_USBDEV_DUALSPEED .hssize = CONFIG_USBADB_EPBULKIN_HSSIZE, #endif #ifdef CONFIG_USBDEV_SUPERSPEED .sssize = CONFIG_USBADB_EPBULKIN_SSSIZE, .compdesc = { .len = USB_SIZEOF_SS_EPCOMPDESC, .type = USB_DESC_TYPE_ENDPOINT_COMPANION, .mxburst = CONFIG_USBADB_EPBULKIN_MAXBURST, .attr = CONFIG_USBADB_EPBULKIN_MAXSTREAM, .wbytes[0] = 0, .wbytes[1] = 0, }, #endif }; static const struct usbdev_epinfo_s g_adb_epbulkout = { .desc = { .len = USB_SIZEOF_EPDESC, .type = USB_DESC_TYPE_ENDPOINT, .addr = USB_DIR_OUT, .attr = USB_EP_ATTR_XFER_BULK | USB_EP_ATTR_NO_SYNC | USB_EP_ATTR_USAGE_DATA, .interval = 0, }, .reqnum = CONFIG_USBADB_NRDREQS, .fssize = CONFIG_USBADB_EPBULKOUT_FSSIZE, #ifdef CONFIG_USBDEV_DUALSPEED .hssize = CONFIG_USBADB_EPBULKOUT_HSSIZE, #endif #ifdef CONFIG_USBDEV_SUPERSPEED .sssize = CONFIG_USBADB_EPBULKOUT_SSSIZE, .compdesc = { .len = USB_SIZEOF_SS_EPCOMPDESC, .type = USB_DESC_TYPE_ENDPOINT_COMPANION, .mxburst = CONFIG_USBADB_EPBULKOUT_MAXBURST, .attr = CONFIG_USBADB_EPBULKOUT_MAXSTREAM, .wbytes[0] = 0, .wbytes[1] = 0, }, #endif }; static const FAR struct usbdev_epinfo_s *g_adb_epinfos[USBADB_NUM_EPS] = { &g_adb_epbulkin, &g_adb_epbulkout, }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: usbclass_mkcfgdesc * * Description: * Construct the configuration descriptor * ****************************************************************************/ static int16_t usbclass_mkcfgdesc(FAR uint8_t *buf, FAR struct usbdev_devinfo_s *devinfo, uint8_t speed, uint8_t type) { FAR uint8_t *epdesc; FAR struct usb_ifdesc_s *dest; uint32_t totallen = 0; int ret; /* Check for switches between high and full speed */ if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG && speed < USB_SPEED_SUPER) { speed = speed == USB_SPEED_HIGH ? USB_SPEED_FULL : USB_SPEED_HIGH; } dest = (FAR struct usb_ifdesc_s *)buf; epdesc = (FAR uint8_t *)(buf + sizeof(g_adb_ifdesc)); memcpy(dest, &g_adb_ifdesc, sizeof(g_adb_ifdesc)); totallen += sizeof(g_adb_ifdesc); ret = usbdev_copy_epdesc((FAR struct usb_epdesc_s *)epdesc, devinfo->epno[USBADB_EP_BULKIN_IDX], speed, &g_adb_epbulkin); totallen += ret; epdesc += ret; ret = usbdev_copy_epdesc((FAR struct usb_epdesc_s *)epdesc, devinfo->epno[USBADB_EP_BULKOUT_IDX], speed, &g_adb_epbulkout); totallen += ret; epdesc += ret; #ifdef CONFIG_USBADB_COMPOSITE /* For composite device, apply possible offset to the interface numbers */ dest->ifno = devinfo->ifnobase; dest->iif = devinfo->strbase + USBADB_INTERFACESTRID; #endif return totallen; } /**************************************************************************** * Name: usbclass_mkstrdesc * * Description: * Construct the string descriptor * ****************************************************************************/ static int usbclass_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) { FAR uint8_t *data = (FAR uint8_t *)(strdesc + 1); FAR const char *str; int len; int ndata; int i; switch (id) { /* Composite driver removes offset before calling mkstrdesc() */ case USBADB_INTERFACESTRID: str = CONFIG_USBADB_INTERFACESTR; break; default: return -EINVAL; } /* The string is utf16-le. The poor man's utf-8 to utf16-le * conversion below will only handle 7-bit en-us ascii */ len = strlen(str); if (len > (USBADB_MAXSTRLEN / 2)) { len = (USBADB_MAXSTRLEN / 2); } for (i = 0, ndata = 0; i < len; i++, ndata += 2) { data[ndata] = str[i]; data[ndata + 1] = 0; } strdesc->len = ndata + 2; strdesc->type = USB_DESC_TYPE_STRING; return strdesc->len; } /**************************************************************************** * Public Functions ****************************************************************************/ #ifndef CONFIG_USBADB_COMPOSITE /**************************************************************************** * Name: usbdev_adb_initialize * * Description: * Initialize the Android Debug Bridge USB device driver. * * Returned Value: * A non-NULL "handle" is returned on success. * ****************************************************************************/ FAR void *usbdev_adb_initialize(void) { struct composite_devdesc_s devdesc; usbdev_adb_get_composite_devdesc(&devdesc); devdesc.devinfo.epno[USBADB_EP_BULKIN_IDX] = USB_EPNO(CONFIG_USBADB_EPBULKIN); devdesc.devinfo.epno[USBADB_EP_BULKOUT_IDX] = USB_EPNO(CONFIG_USBADB_EPBULKOUT); return usbdev_fs_initialize(&g_adb_devdescs, &devdesc); } /**************************************************************************** * Name: usbdev_adb_uninitialize * * Description: * Uninitialize the Android Debug Bridge USB device driver. * ****************************************************************************/ void usbdev_adb_uninitialize(FAR void *handle) { usbdev_fs_uninitialize(handle); } #endif /**************************************************************************** * Name: usbdev_adb_get_composite_devdesc * * Returned Value: * None * ****************************************************************************/ void usbdev_adb_get_composite_devdesc(FAR struct composite_devdesc_s *dev) { memset(dev, 0, sizeof(struct composite_devdesc_s)); dev->classobject = usbdev_fs_classobject; dev->uninitialize = usbdev_fs_classuninitialize; dev->mkconfdesc = usbclass_mkcfgdesc, dev->mkstrdesc = usbclass_mkstrdesc, dev->nconfigs = USBADB_NCONFIGS; dev->configid = 1; #ifdef CONFIG_USBDEV_SUPERSPEED dev->cfgdescsize = sizeof(g_adb_ifdesc) + USB_SIZEOF_EPDESC * 2 + USB_SIZEOF_SS_EPCOMPDESC * 2; #else dev->cfgdescsize = sizeof(g_adb_ifdesc) + 2 * USB_SIZEOF_EPDESC; #endif dev->devinfo.ninterfaces = 1; dev->devinfo.nstrings = USBADB_NSTRIDS; dev->devinfo.nendpoints = USBADB_NUM_EPS; dev->devinfo.epinfos = g_adb_epinfos; dev->devinfo.name = USBADB_CHARDEV_PATH; }