13e420a3eSRuslan Bukin /*- 23e420a3eSRuslan Bukin * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 33e420a3eSRuslan Bukin * All rights reserved. 43e420a3eSRuslan Bukin * 53e420a3eSRuslan Bukin * This software was developed by SRI International and the University of 63e420a3eSRuslan Bukin * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 73e420a3eSRuslan Bukin * ("CTSRD"), as part of the DARPA CRASH research programme. 83e420a3eSRuslan Bukin * 93e420a3eSRuslan Bukin * Redistribution and use in source and binary forms, with or without 103e420a3eSRuslan Bukin * modification, are permitted provided that the following conditions 113e420a3eSRuslan Bukin * are met: 123e420a3eSRuslan Bukin * 1. Redistributions of source code must retain the above copyright 133e420a3eSRuslan Bukin * notice, this list of conditions and the following disclaimer. 143e420a3eSRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 153e420a3eSRuslan Bukin * notice, this list of conditions and the following disclaimer in the 163e420a3eSRuslan Bukin * documentation and/or other materials provided with the distribution. 173e420a3eSRuslan Bukin * 183e420a3eSRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 193e420a3eSRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 203e420a3eSRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 213e420a3eSRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 223e420a3eSRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 233e420a3eSRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 243e420a3eSRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 253e420a3eSRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 263e420a3eSRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 273e420a3eSRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 283e420a3eSRuslan Bukin * SUCH DAMAGE. 293e420a3eSRuslan Bukin */ 303e420a3eSRuslan Bukin /* 313e420a3eSRuslan Bukin * This file contains the USB template for USB Networking and Serial 323e420a3eSRuslan Bukin */ 333e420a3eSRuslan Bukin 343e420a3eSRuslan Bukin #include <sys/cdefs.h> 353e420a3eSRuslan Bukin __FBSDID("$FreeBSD$"); 363e420a3eSRuslan Bukin 373e420a3eSRuslan Bukin #ifdef USB_GLOBAL_INCLUDE_FILE 383e420a3eSRuslan Bukin #include USB_GLOBAL_INCLUDE_FILE 393e420a3eSRuslan Bukin #else 403e420a3eSRuslan Bukin #include <sys/stdint.h> 413e420a3eSRuslan Bukin #include <sys/stddef.h> 423e420a3eSRuslan Bukin #include <sys/param.h> 433e420a3eSRuslan Bukin #include <sys/queue.h> 443e420a3eSRuslan Bukin #include <sys/types.h> 453e420a3eSRuslan Bukin #include <sys/systm.h> 463e420a3eSRuslan Bukin #include <sys/kernel.h> 473e420a3eSRuslan Bukin #include <sys/bus.h> 483e420a3eSRuslan Bukin #include <sys/module.h> 493e420a3eSRuslan Bukin #include <sys/lock.h> 503e420a3eSRuslan Bukin #include <sys/mutex.h> 513e420a3eSRuslan Bukin #include <sys/condvar.h> 523e420a3eSRuslan Bukin #include <sys/sysctl.h> 533e420a3eSRuslan Bukin #include <sys/sx.h> 543e420a3eSRuslan Bukin #include <sys/unistd.h> 553e420a3eSRuslan Bukin #include <sys/callout.h> 563e420a3eSRuslan Bukin #include <sys/malloc.h> 573e420a3eSRuslan Bukin #include <sys/priv.h> 583e420a3eSRuslan Bukin 593e420a3eSRuslan Bukin #include <dev/usb/usb.h> 603e420a3eSRuslan Bukin #include <dev/usb/usbdi.h> 613e420a3eSRuslan Bukin #include <dev/usb/usb_core.h> 623e420a3eSRuslan Bukin #include <dev/usb/usb_cdc.h> 633e420a3eSRuslan Bukin 643e420a3eSRuslan Bukin #include <dev/usb/template/usb_template.h> 653e420a3eSRuslan Bukin #endif /* USB_GLOBAL_INCLUDE_FILE */ 663e420a3eSRuslan Bukin 673e420a3eSRuslan Bukin #define MODEM_IFACE_0 0 683e420a3eSRuslan Bukin #define MODEM_IFACE_1 1 693e420a3eSRuslan Bukin 703e420a3eSRuslan Bukin enum { 713e420a3eSRuslan Bukin STRING_LANG_INDEX, 723e420a3eSRuslan Bukin STRING_MODEM_INDEX, 733e420a3eSRuslan Bukin STRING_ETH_MAC_INDEX, 743e420a3eSRuslan Bukin STRING_ETH_CONTROL_INDEX, 753e420a3eSRuslan Bukin STRING_ETH_DATA_INDEX, 763e420a3eSRuslan Bukin STRING_ETH_CONFIG_INDEX, 773e420a3eSRuslan Bukin STRING_CONFIG_INDEX, 783e420a3eSRuslan Bukin STRING_VENDOR_INDEX, 793e420a3eSRuslan Bukin STRING_PRODUCT_INDEX, 803e420a3eSRuslan Bukin STRING_SERIAL_INDEX, 813e420a3eSRuslan Bukin STRING_MAX, 823e420a3eSRuslan Bukin }; 833e420a3eSRuslan Bukin 843e420a3eSRuslan Bukin #define STRING_MODEM \ 853e420a3eSRuslan Bukin "U\0S\0B\0 \0M\0o\0d\0e\0m\0 \0I\0n\0t\0e\0r\0f\0a\0c\0e" 863e420a3eSRuslan Bukin 873e420a3eSRuslan Bukin #define STRING_ETH_MAC \ 883e420a3eSRuslan Bukin "2\0A\0002\0003\0004\0005\0006\0007\08\09\0A\0B" 893e420a3eSRuslan Bukin 903e420a3eSRuslan Bukin #define STRING_ETH_CONTROL \ 913e420a3eSRuslan Bukin "U\0S\0B\0 \0E\0t\0h\0e\0r\0n\0e\0t\0 " \ 923e420a3eSRuslan Bukin "\0C\0o\0m\0m\0 \0I\0n\0t\0e\0r\0f\0a\0c\0e" 933e420a3eSRuslan Bukin 943e420a3eSRuslan Bukin #define STRING_ETH_DATA \ 953e420a3eSRuslan Bukin "U\0S\0B\0 \0E\0t\0h\0e\0r\0n\0e\0t\0 \0D\0a\0t\0a\0 " \ 963e420a3eSRuslan Bukin "\0I\0n\0t\0e\0r\0f\0a\0c\0e" 973e420a3eSRuslan Bukin 983e420a3eSRuslan Bukin #define STRING_CONFIG \ 993e420a3eSRuslan Bukin "D\0e\0f\0a\0u\0l\0t\0 \0c\0o\0n\0f\0i\0g\0u\0r\0a\0t\0i\0o\0n" 1003e420a3eSRuslan Bukin 1013e420a3eSRuslan Bukin #define STRING_VENDOR \ 1023e420a3eSRuslan Bukin "T\0h\0e\0 \0F\0r\0e\0e\0B\0S\0D\0 \0P\0r\0o\0j\0e\0c\0t" 1033e420a3eSRuslan Bukin 1043e420a3eSRuslan Bukin #define STRING_PRODUCT \ 1053e420a3eSRuslan Bukin "S\0E\0R\0I\0A\0L\0N\0E\0T" 1063e420a3eSRuslan Bukin 1073e420a3eSRuslan Bukin #define STRING_SERIAL \ 1083e420a3eSRuslan Bukin "J\0a\0n\0u\0a\0r\0y\0 \0002\0000\0001\0005" 1093e420a3eSRuslan Bukin 1103e420a3eSRuslan Bukin /* make the real string descriptors */ 1113e420a3eSRuslan Bukin 1123e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_MODEM, string_modem); 1133e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_ETH_MAC, string_eth_mac); 1143e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_ETH_CONTROL, string_eth_control); 1153e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_ETH_DATA, string_eth_data); 1163e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_CONFIG, string_serialnet_config); 1173e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_VENDOR, string_serialnet_vendor); 1183e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_PRODUCT, string_serialnet_product); 1193e420a3eSRuslan Bukin USB_MAKE_STRING_DESC(STRING_SERIAL, string_serialnet_serial); 1203e420a3eSRuslan Bukin 1213e420a3eSRuslan Bukin /* prototypes */ 1223e420a3eSRuslan Bukin 1233e420a3eSRuslan Bukin static usb_temp_get_string_desc_t serialnet_get_string_desc; 1243e420a3eSRuslan Bukin 1253e420a3eSRuslan Bukin static const struct usb_cdc_union_descriptor eth_union_desc = { 1263e420a3eSRuslan Bukin .bLength = sizeof(eth_union_desc), 1273e420a3eSRuslan Bukin .bDescriptorType = UDESC_CS_INTERFACE, 1283e420a3eSRuslan Bukin .bDescriptorSubtype = UDESCSUB_CDC_UNION, 1293e420a3eSRuslan Bukin .bMasterInterface = 0, /* this is automatically updated */ 1303e420a3eSRuslan Bukin .bSlaveInterface[0] = 1, /* this is automatically updated */ 1313e420a3eSRuslan Bukin }; 1323e420a3eSRuslan Bukin 1333e420a3eSRuslan Bukin static const struct usb_cdc_header_descriptor eth_header_desc = { 1343e420a3eSRuslan Bukin .bLength = sizeof(eth_header_desc), 1353e420a3eSRuslan Bukin .bDescriptorType = UDESC_CS_INTERFACE, 1363e420a3eSRuslan Bukin .bDescriptorSubtype = UDESCSUB_CDC_HEADER, 1373e420a3eSRuslan Bukin .bcdCDC[0] = 0x10, 1383e420a3eSRuslan Bukin .bcdCDC[1] = 0x01, 1393e420a3eSRuslan Bukin }; 1403e420a3eSRuslan Bukin 1413e420a3eSRuslan Bukin static const struct usb_cdc_ethernet_descriptor eth_enf_desc = { 1423e420a3eSRuslan Bukin .bLength = sizeof(eth_enf_desc), 1433e420a3eSRuslan Bukin .bDescriptorType = UDESC_CS_INTERFACE, 1443e420a3eSRuslan Bukin .bDescriptorSubtype = UDESCSUB_CDC_ENF, 1453e420a3eSRuslan Bukin .iMacAddress = STRING_ETH_MAC_INDEX, 1463e420a3eSRuslan Bukin .bmEthernetStatistics = {0, 0, 0, 0}, 1473e420a3eSRuslan Bukin .wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */ 1483e420a3eSRuslan Bukin .wNumberMCFilters = {0, 0}, 1493e420a3eSRuslan Bukin .bNumberPowerFilters = 0, 1503e420a3eSRuslan Bukin }; 1513e420a3eSRuslan Bukin 1523e420a3eSRuslan Bukin static const void *eth_control_if_desc[] = { 1533e420a3eSRuslan Bukin ð_union_desc, 1543e420a3eSRuslan Bukin ð_header_desc, 1553e420a3eSRuslan Bukin ð_enf_desc, 1563e420a3eSRuslan Bukin NULL, 1573e420a3eSRuslan Bukin }; 1583e420a3eSRuslan Bukin 1593e420a3eSRuslan Bukin static const struct usb_temp_packet_size bulk_mps = { 1603e420a3eSRuslan Bukin .mps[USB_SPEED_FULL] = 64, 1613e420a3eSRuslan Bukin .mps[USB_SPEED_HIGH] = 512, 1623e420a3eSRuslan Bukin }; 1633e420a3eSRuslan Bukin 1643e420a3eSRuslan Bukin static const struct usb_temp_packet_size intr_mps = { 1653e420a3eSRuslan Bukin .mps[USB_SPEED_FULL] = 8, 1663e420a3eSRuslan Bukin .mps[USB_SPEED_HIGH] = 8, 1673e420a3eSRuslan Bukin }; 1683e420a3eSRuslan Bukin 1693e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc bulk_in_ep = { 1703e420a3eSRuslan Bukin .pPacketSize = &bulk_mps, 1713e420a3eSRuslan Bukin #ifdef USB_HIP_IN_EP_0 1723e420a3eSRuslan Bukin .bEndpointAddress = USB_HIP_IN_EP_0, 1733e420a3eSRuslan Bukin #else 1743e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_IN, 1753e420a3eSRuslan Bukin #endif 1763e420a3eSRuslan Bukin .bmAttributes = UE_BULK, 1773e420a3eSRuslan Bukin }; 1783e420a3eSRuslan Bukin 1793e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc bulk_out_ep = { 1803e420a3eSRuslan Bukin .pPacketSize = &bulk_mps, 1813e420a3eSRuslan Bukin #ifdef USB_HIP_OUT_EP_0 1823e420a3eSRuslan Bukin .bEndpointAddress = USB_HIP_OUT_EP_0, 1833e420a3eSRuslan Bukin #else 1843e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_OUT, 1853e420a3eSRuslan Bukin #endif 1863e420a3eSRuslan Bukin .bmAttributes = UE_BULK, 1873e420a3eSRuslan Bukin }; 1883e420a3eSRuslan Bukin 1893e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc intr_in_ep = { 1903e420a3eSRuslan Bukin .pPacketSize = &intr_mps, 1913e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_IN, 1923e420a3eSRuslan Bukin .bmAttributes = UE_INTERRUPT, 1933e420a3eSRuslan Bukin }; 1943e420a3eSRuslan Bukin 1953e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = { 1963e420a3eSRuslan Bukin &intr_in_ep, 1973e420a3eSRuslan Bukin NULL, 1983e420a3eSRuslan Bukin }; 1993e420a3eSRuslan Bukin 2003e420a3eSRuslan Bukin static const struct usb_temp_interface_desc eth_control_interface = { 2013e420a3eSRuslan Bukin .ppEndpoints = eth_intr_endpoints, 2023e420a3eSRuslan Bukin .ppRawDesc = eth_control_if_desc, 2033e420a3eSRuslan Bukin .bInterfaceClass = UICLASS_CDC, 2043e420a3eSRuslan Bukin .bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 205*4ffeccf1SEdward Tomasz Napierala .bInterfaceProtocol = UIPROTO_CDC_NONE, 2063e420a3eSRuslan Bukin .iInterface = STRING_ETH_CONTROL_INDEX, 2073e420a3eSRuslan Bukin }; 2083e420a3eSRuslan Bukin 2093e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc *eth_data_endpoints[] = { 2103e420a3eSRuslan Bukin &bulk_in_ep, 2113e420a3eSRuslan Bukin &bulk_out_ep, 2123e420a3eSRuslan Bukin NULL, 2133e420a3eSRuslan Bukin }; 2143e420a3eSRuslan Bukin 2153e420a3eSRuslan Bukin static const struct usb_temp_interface_desc eth_data_null_interface = { 2163e420a3eSRuslan Bukin .ppEndpoints = NULL, /* no endpoints */ 2173e420a3eSRuslan Bukin .bInterfaceClass = UICLASS_CDC_DATA, 218*4ffeccf1SEdward Tomasz Napierala .bInterfaceSubClass = UISUBCLASS_DATA, 2193e420a3eSRuslan Bukin .bInterfaceProtocol = 0, 2203e420a3eSRuslan Bukin .iInterface = STRING_ETH_DATA_INDEX, 2213e420a3eSRuslan Bukin }; 2223e420a3eSRuslan Bukin 2233e420a3eSRuslan Bukin static const struct usb_temp_interface_desc eth_data_interface = { 2243e420a3eSRuslan Bukin .ppEndpoints = eth_data_endpoints, 2253e420a3eSRuslan Bukin .bInterfaceClass = UICLASS_CDC_DATA, 2263e420a3eSRuslan Bukin .bInterfaceSubClass = UISUBCLASS_DATA, 2273e420a3eSRuslan Bukin .bInterfaceProtocol = 0, 2283e420a3eSRuslan Bukin .iInterface = STRING_ETH_DATA_INDEX, 2293e420a3eSRuslan Bukin .isAltInterface = 1, /* this is an alternate setting */ 2303e420a3eSRuslan Bukin }; 2313e420a3eSRuslan Bukin 2323e420a3eSRuslan Bukin static const struct usb_temp_packet_size modem_bulk_mps = { 2333e420a3eSRuslan Bukin .mps[USB_SPEED_LOW] = 8, 2343e420a3eSRuslan Bukin .mps[USB_SPEED_FULL] = 64, 2353e420a3eSRuslan Bukin .mps[USB_SPEED_HIGH] = 512, 2363e420a3eSRuslan Bukin }; 2373e420a3eSRuslan Bukin 2383e420a3eSRuslan Bukin static const struct usb_temp_packet_size modem_intr_mps = { 2393e420a3eSRuslan Bukin .mps[USB_SPEED_LOW] = 8, 2403e420a3eSRuslan Bukin .mps[USB_SPEED_FULL] = 8, 2413e420a3eSRuslan Bukin .mps[USB_SPEED_HIGH] = 8, 2423e420a3eSRuslan Bukin }; 2433e420a3eSRuslan Bukin 2443e420a3eSRuslan Bukin static const struct usb_temp_interval modem_intr_interval = { 2453e420a3eSRuslan Bukin .bInterval[USB_SPEED_LOW] = 8, /* 8ms */ 2463e420a3eSRuslan Bukin .bInterval[USB_SPEED_FULL] = 8, /* 8ms */ 2473e420a3eSRuslan Bukin .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */ 2483e420a3eSRuslan Bukin }; 2493e420a3eSRuslan Bukin 2503e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc modem_ep_0 = { 2513e420a3eSRuslan Bukin .pPacketSize = &modem_intr_mps, 2523e420a3eSRuslan Bukin .pIntervals = &modem_intr_interval, 2533e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_IN, 2543e420a3eSRuslan Bukin .bmAttributes = UE_INTERRUPT, 2553e420a3eSRuslan Bukin }; 2563e420a3eSRuslan Bukin 2573e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc modem_ep_1 = { 2583e420a3eSRuslan Bukin .pPacketSize = &modem_bulk_mps, 2593e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_OUT, 2603e420a3eSRuslan Bukin .bmAttributes = UE_BULK, 2613e420a3eSRuslan Bukin }; 2623e420a3eSRuslan Bukin 2633e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc modem_ep_2 = { 2643e420a3eSRuslan Bukin .pPacketSize = &modem_bulk_mps, 2653e420a3eSRuslan Bukin .bEndpointAddress = UE_DIR_IN, 2663e420a3eSRuslan Bukin .bmAttributes = UE_BULK, 2673e420a3eSRuslan Bukin }; 2683e420a3eSRuslan Bukin 2693e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 2703e420a3eSRuslan Bukin &modem_ep_0, 2713e420a3eSRuslan Bukin NULL, 2723e420a3eSRuslan Bukin }; 2733e420a3eSRuslan Bukin 2743e420a3eSRuslan Bukin static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 2753e420a3eSRuslan Bukin &modem_ep_1, 2763e420a3eSRuslan Bukin &modem_ep_2, 2773e420a3eSRuslan Bukin NULL, 2783e420a3eSRuslan Bukin }; 2793e420a3eSRuslan Bukin 2803e420a3eSRuslan Bukin static const uint8_t modem_raw_desc_0[] = { 2813e420a3eSRuslan Bukin 0x05, 0x24, 0x00, 0x10, 0x01 2823e420a3eSRuslan Bukin }; 2833e420a3eSRuslan Bukin 2843e420a3eSRuslan Bukin static const uint8_t modem_raw_desc_1[] = { 2853e420a3eSRuslan Bukin 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 2863e420a3eSRuslan Bukin }; 2873e420a3eSRuslan Bukin 2883e420a3eSRuslan Bukin static const uint8_t modem_raw_desc_2[] = { 2893e420a3eSRuslan Bukin 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 2903e420a3eSRuslan Bukin }; 2913e420a3eSRuslan Bukin 2923e420a3eSRuslan Bukin static const uint8_t modem_raw_desc_3[] = { 2933e420a3eSRuslan Bukin 0x04, 0x24, 0x02, 0x07 2943e420a3eSRuslan Bukin }; 2953e420a3eSRuslan Bukin 2963e420a3eSRuslan Bukin static const void *modem_iface_0_desc[] = { 2973e420a3eSRuslan Bukin &modem_raw_desc_0, 2983e420a3eSRuslan Bukin &modem_raw_desc_1, 2993e420a3eSRuslan Bukin &modem_raw_desc_2, 3003e420a3eSRuslan Bukin &modem_raw_desc_3, 3013e420a3eSRuslan Bukin NULL, 3023e420a3eSRuslan Bukin }; 3033e420a3eSRuslan Bukin 3043e420a3eSRuslan Bukin static const struct usb_temp_interface_desc modem_iface_0 = { 3053e420a3eSRuslan Bukin .ppRawDesc = modem_iface_0_desc, 3063e420a3eSRuslan Bukin .ppEndpoints = modem_iface_0_ep, 307*4ffeccf1SEdward Tomasz Napierala .bInterfaceClass = UICLASS_CDC, 308*4ffeccf1SEdward Tomasz Napierala .bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL, 309*4ffeccf1SEdward Tomasz Napierala .bInterfaceProtocol = UIPROTO_CDC_AT, 3103e420a3eSRuslan Bukin .iInterface = STRING_MODEM_INDEX, 3113e420a3eSRuslan Bukin }; 3123e420a3eSRuslan Bukin 3133e420a3eSRuslan Bukin static const struct usb_temp_interface_desc modem_iface_1 = { 3143e420a3eSRuslan Bukin .ppEndpoints = modem_iface_1_ep, 315*4ffeccf1SEdward Tomasz Napierala .bInterfaceClass = UICLASS_CDC_DATA, 316*4ffeccf1SEdward Tomasz Napierala .bInterfaceSubClass = UISUBCLASS_DATA, 3173e420a3eSRuslan Bukin .bInterfaceProtocol = 0, 3183e420a3eSRuslan Bukin .iInterface = STRING_MODEM_INDEX, 3193e420a3eSRuslan Bukin }; 3203e420a3eSRuslan Bukin 3213e420a3eSRuslan Bukin static const struct usb_temp_interface_desc *serialnet_interfaces[] = { 3223e420a3eSRuslan Bukin &modem_iface_0, 3233e420a3eSRuslan Bukin &modem_iface_1, 3243e420a3eSRuslan Bukin ð_control_interface, 3253e420a3eSRuslan Bukin ð_data_null_interface, 3263e420a3eSRuslan Bukin ð_data_interface, 3273e420a3eSRuslan Bukin NULL, 3283e420a3eSRuslan Bukin }; 3293e420a3eSRuslan Bukin 3303e420a3eSRuslan Bukin static const struct usb_temp_config_desc serialnet_config_desc = { 3313e420a3eSRuslan Bukin .ppIfaceDesc = serialnet_interfaces, 3323e420a3eSRuslan Bukin .bmAttributes = UC_BUS_POWERED, 3333e420a3eSRuslan Bukin .bMaxPower = 25, /* 50 mA */ 3343e420a3eSRuslan Bukin .iConfiguration = STRING_CONFIG_INDEX, 3353e420a3eSRuslan Bukin }; 3363e420a3eSRuslan Bukin static const struct usb_temp_config_desc *serialnet_configs[] = { 3373e420a3eSRuslan Bukin &serialnet_config_desc, 3383e420a3eSRuslan Bukin NULL, 3393e420a3eSRuslan Bukin }; 3403e420a3eSRuslan Bukin 3413e420a3eSRuslan Bukin const struct usb_temp_device_desc usb_template_serialnet = { 3423e420a3eSRuslan Bukin .getStringDesc = &serialnet_get_string_desc, 3433e420a3eSRuslan Bukin .ppConfigDesc = serialnet_configs, 3443e420a3eSRuslan Bukin .idVendor = USB_TEMPLATE_VENDOR, 3453e420a3eSRuslan Bukin .idProduct = 0x0001, 3463e420a3eSRuslan Bukin .bcdDevice = 0x0100, 3473e420a3eSRuslan Bukin .bDeviceClass = UDCLASS_COMM, 3483e420a3eSRuslan Bukin .bDeviceSubClass = 0, 3493e420a3eSRuslan Bukin .bDeviceProtocol = 0, 3503e420a3eSRuslan Bukin .iManufacturer = STRING_VENDOR_INDEX, 3513e420a3eSRuslan Bukin .iProduct = STRING_PRODUCT_INDEX, 3523e420a3eSRuslan Bukin .iSerialNumber = STRING_SERIAL_INDEX, 3533e420a3eSRuslan Bukin }; 3543e420a3eSRuslan Bukin 3553e420a3eSRuslan Bukin /*------------------------------------------------------------------------* 3563e420a3eSRuslan Bukin * serialnet_get_string_desc 3573e420a3eSRuslan Bukin * 3583e420a3eSRuslan Bukin * Return values: 3593e420a3eSRuslan Bukin * NULL: Failure. No such string. 3603e420a3eSRuslan Bukin * Else: Success. Pointer to string descriptor is returned. 3613e420a3eSRuslan Bukin *------------------------------------------------------------------------*/ 3623e420a3eSRuslan Bukin static const void * 3633e420a3eSRuslan Bukin serialnet_get_string_desc(uint16_t lang_id, uint8_t string_index) 3643e420a3eSRuslan Bukin { 3653e420a3eSRuslan Bukin static const void *ptr[STRING_MAX] = { 3663e420a3eSRuslan Bukin [STRING_LANG_INDEX] = &usb_string_lang_en, 3673e420a3eSRuslan Bukin [STRING_MODEM_INDEX] = &string_modem, 3683e420a3eSRuslan Bukin [STRING_ETH_MAC_INDEX] = &string_eth_mac, 3693e420a3eSRuslan Bukin [STRING_ETH_CONTROL_INDEX] = &string_eth_control, 3703e420a3eSRuslan Bukin [STRING_ETH_DATA_INDEX] = &string_eth_data, 3713e420a3eSRuslan Bukin [STRING_CONFIG_INDEX] = &string_serialnet_config, 3723e420a3eSRuslan Bukin [STRING_VENDOR_INDEX] = &string_serialnet_vendor, 3733e420a3eSRuslan Bukin [STRING_PRODUCT_INDEX] = &string_serialnet_product, 3743e420a3eSRuslan Bukin [STRING_SERIAL_INDEX] = &string_serialnet_serial, 3753e420a3eSRuslan Bukin }; 3763e420a3eSRuslan Bukin 3773e420a3eSRuslan Bukin if (string_index == 0) { 3783e420a3eSRuslan Bukin return (&usb_string_lang_en); 3793e420a3eSRuslan Bukin } 3803e420a3eSRuslan Bukin if (lang_id != 0x0409) { 3813e420a3eSRuslan Bukin return (NULL); 3823e420a3eSRuslan Bukin } 3833e420a3eSRuslan Bukin if (string_index < STRING_MAX) { 3843e420a3eSRuslan Bukin return (ptr[string_index]); 3853e420a3eSRuslan Bukin } 3863e420a3eSRuslan Bukin return (NULL); 3873e420a3eSRuslan Bukin } 388