xref: /freebsd/sys/dev/usb/template/usb_template_multi.c (revision ca48e43ba9ee73a07cdbad8365117793b01273bb)
13dc87e52SEdward Tomasz Napierala /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33dc87e52SEdward Tomasz Napierala  *
43dc87e52SEdward Tomasz Napierala  * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
53dc87e52SEdward Tomasz Napierala  * Copyright (c) 2018 The FreeBSD Foundation
63dc87e52SEdward Tomasz Napierala  * All rights reserved.
73dc87e52SEdward Tomasz Napierala  *
83dc87e52SEdward Tomasz Napierala  * This software was developed by SRI International and the University of
93dc87e52SEdward Tomasz Napierala  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
103dc87e52SEdward Tomasz Napierala  * ("CTSRD"), as part of the DARPA CRASH research programme.
113dc87e52SEdward Tomasz Napierala  *
123dc87e52SEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
133dc87e52SEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
143dc87e52SEdward Tomasz Napierala  *
153dc87e52SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
163dc87e52SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
173dc87e52SEdward Tomasz Napierala  * are met:
183dc87e52SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
193dc87e52SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
203dc87e52SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
213dc87e52SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
223dc87e52SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
233dc87e52SEdward Tomasz Napierala  *
243dc87e52SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
253dc87e52SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
263dc87e52SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
273dc87e52SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
283dc87e52SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
293dc87e52SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
303dc87e52SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
313dc87e52SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
323dc87e52SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
333dc87e52SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
343dc87e52SEdward Tomasz Napierala  * SUCH DAMAGE.
353dc87e52SEdward Tomasz Napierala  */
363dc87e52SEdward Tomasz Napierala /*
373dc87e52SEdward Tomasz Napierala  * USB template for CDC ACM (serial), CDC ECM (network), and CDC MSC (storage).
383dc87e52SEdward Tomasz Napierala  */
393dc87e52SEdward Tomasz Napierala 
403dc87e52SEdward Tomasz Napierala #ifdef USB_GLOBAL_INCLUDE_FILE
413dc87e52SEdward Tomasz Napierala #include USB_GLOBAL_INCLUDE_FILE
423dc87e52SEdward Tomasz Napierala #else
433dc87e52SEdward Tomasz Napierala #include <sys/stdint.h>
443dc87e52SEdward Tomasz Napierala #include <sys/stddef.h>
453dc87e52SEdward Tomasz Napierala #include <sys/param.h>
463dc87e52SEdward Tomasz Napierala #include <sys/queue.h>
473dc87e52SEdward Tomasz Napierala #include <sys/types.h>
483dc87e52SEdward Tomasz Napierala #include <sys/systm.h>
493dc87e52SEdward Tomasz Napierala #include <sys/kernel.h>
503dc87e52SEdward Tomasz Napierala #include <sys/bus.h>
513dc87e52SEdward Tomasz Napierala #include <sys/module.h>
523dc87e52SEdward Tomasz Napierala #include <sys/lock.h>
533dc87e52SEdward Tomasz Napierala #include <sys/mutex.h>
543dc87e52SEdward Tomasz Napierala #include <sys/condvar.h>
553dc87e52SEdward Tomasz Napierala #include <sys/sysctl.h>
563dc87e52SEdward Tomasz Napierala #include <sys/sx.h>
573dc87e52SEdward Tomasz Napierala #include <sys/unistd.h>
583dc87e52SEdward Tomasz Napierala #include <sys/callout.h>
593dc87e52SEdward Tomasz Napierala #include <sys/malloc.h>
603dc87e52SEdward Tomasz Napierala #include <sys/priv.h>
613dc87e52SEdward Tomasz Napierala 
623dc87e52SEdward Tomasz Napierala #include <dev/usb/usb.h>
633dc87e52SEdward Tomasz Napierala #include <dev/usb/usbdi.h>
643dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_core.h>
653dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_cdc.h>
663dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_ioctl.h>
673dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_util.h>
683dc87e52SEdward Tomasz Napierala 
693dc87e52SEdward Tomasz Napierala #include <dev/usb/template/usb_template.h>
703dc87e52SEdward Tomasz Napierala #endif		/* USB_GLOBAL_INCLUDE_FILE */
713dc87e52SEdward Tomasz Napierala 
723dc87e52SEdward Tomasz Napierala #define	MODEM_IFACE_0 0
733dc87e52SEdward Tomasz Napierala #define	MODEM_IFACE_1 1
743dc87e52SEdward Tomasz Napierala 
753dc87e52SEdward Tomasz Napierala enum {
763dc87e52SEdward Tomasz Napierala 	MULTI_LANG_INDEX,
773dc87e52SEdward Tomasz Napierala 	MULTI_MODEM_INDEX,
783dc87e52SEdward Tomasz Napierala 	MULTI_ETH_MAC_INDEX,
793dc87e52SEdward Tomasz Napierala 	MULTI_ETH_CONTROL_INDEX,
803dc87e52SEdward Tomasz Napierala 	MULTI_ETH_DATA_INDEX,
813dc87e52SEdward Tomasz Napierala 	MULTI_STORAGE_INDEX,
823dc87e52SEdward Tomasz Napierala 	MULTI_CONFIGURATION_INDEX,
833dc87e52SEdward Tomasz Napierala 	MULTI_MANUFACTURER_INDEX,
843dc87e52SEdward Tomasz Napierala 	MULTI_PRODUCT_INDEX,
853dc87e52SEdward Tomasz Napierala 	MULTI_SERIAL_NUMBER_INDEX,
863dc87e52SEdward Tomasz Napierala 	MULTI_MAX_INDEX,
873dc87e52SEdward Tomasz Napierala };
883dc87e52SEdward Tomasz Napierala 
891558eec6SEdward Tomasz Napierala #define	MULTI_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
90d01c1c8bSEdward Tomasz Napierala #define	MULTI_DEFAULT_PRODUCT_ID	0x05dc
91ac4a7f30SEdward Tomasz Napierala #define	MULTI_DEFAULT_MODEM		"Virtual serial port"
923dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_MAC		"2A02030405060789AB"
933dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_CONTROL	"Ethernet Comm Interface"
943dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_DATA		"Ethernet Data Interface"
953dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_STORAGE		"Mass Storage Interface"
963dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_CONFIGURATION	"Default configuration"
97d01c1c8bSEdward Tomasz Napierala #define	MULTI_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
983dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_PRODUCT		"Multifunction Device"
99733efc21SEdward Tomasz Napierala /*
100733efc21SEdward Tomasz Napierala  * The reason for this being called like this is that OSX
101733efc21SEdward Tomasz Napierala  * derives the device node name from it, resulting in a somewhat
102733efc21SEdward Tomasz Napierala  * user-friendly "/dev/cu.usbmodemFreeBSD1".  And yes, the "1"
103733efc21SEdward Tomasz Napierala  * needs to be there, otherwise OSX will mangle it.
104733efc21SEdward Tomasz Napierala  */
105733efc21SEdward Tomasz Napierala #define MULTI_DEFAULT_SERIAL_NUMBER	"FreeBSD1"
1063dc87e52SEdward Tomasz Napierala 
1073dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_modem;
1083dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_mac;
1093dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_control;
1103dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_data;
1113dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_storage;
1123dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_configuration;
1133dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_manufacturer;
1143dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_product;
1153dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_serial_number;
1163dc87e52SEdward Tomasz Napierala 
1173dc87e52SEdward Tomasz Napierala static struct sysctl_ctx_list		multi_ctx_list;
1183dc87e52SEdward Tomasz Napierala 
1193dc87e52SEdward Tomasz Napierala /* prototypes */
1203dc87e52SEdward Tomasz Napierala 
1213dc87e52SEdward Tomasz Napierala static usb_temp_get_string_desc_t multi_get_string_desc;
1223dc87e52SEdward Tomasz Napierala 
1233dc87e52SEdward Tomasz Napierala static const struct usb_cdc_union_descriptor eth_union_desc = {
1243dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_union_desc),
1253dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1263dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_UNION,
1273dc87e52SEdward Tomasz Napierala 	.bMasterInterface = 0,		/* this is automatically updated */
1283dc87e52SEdward Tomasz Napierala 	.bSlaveInterface[0] = 1,	/* this is automatically updated */
1293dc87e52SEdward Tomasz Napierala };
1303dc87e52SEdward Tomasz Napierala 
1313dc87e52SEdward Tomasz Napierala static const struct usb_cdc_header_descriptor eth_header_desc = {
1323dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_header_desc),
1333dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1343dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_HEADER,
1353dc87e52SEdward Tomasz Napierala 	.bcdCDC[0] = 0x10,
1363dc87e52SEdward Tomasz Napierala 	.bcdCDC[1] = 0x01,
1373dc87e52SEdward Tomasz Napierala };
1383dc87e52SEdward Tomasz Napierala 
1393dc87e52SEdward Tomasz Napierala static const struct usb_cdc_ethernet_descriptor eth_enf_desc = {
1403dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_enf_desc),
1413dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1423dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_ENF,
1433dc87e52SEdward Tomasz Napierala 	.iMacAddress = MULTI_ETH_MAC_INDEX,
1443dc87e52SEdward Tomasz Napierala 	.bmEthernetStatistics = {0, 0, 0, 0},
1453dc87e52SEdward Tomasz Napierala 	.wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */
1463dc87e52SEdward Tomasz Napierala 	.wNumberMCFilters = {0, 0},
1473dc87e52SEdward Tomasz Napierala 	.bNumberPowerFilters = 0,
1483dc87e52SEdward Tomasz Napierala };
1493dc87e52SEdward Tomasz Napierala 
1503dc87e52SEdward Tomasz Napierala static const void *eth_control_if_desc[] = {
1513dc87e52SEdward Tomasz Napierala 	&eth_union_desc,
1523dc87e52SEdward Tomasz Napierala 	&eth_header_desc,
1533dc87e52SEdward Tomasz Napierala 	&eth_enf_desc,
1543dc87e52SEdward Tomasz Napierala 	NULL,
1553dc87e52SEdward Tomasz Napierala };
1563dc87e52SEdward Tomasz Napierala 
1573dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size bulk_mps = {
1583dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
1593dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
1603dc87e52SEdward Tomasz Napierala };
1613dc87e52SEdward Tomasz Napierala 
1623dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size intr_mps = {
1633dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 8,
1643dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 8,
1653dc87e52SEdward Tomasz Napierala };
1663dc87e52SEdward Tomasz Napierala 
1673dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc bulk_in_ep = {
1683dc87e52SEdward Tomasz Napierala 	.pPacketSize = &bulk_mps,
1693dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_IN_EP_0
1703dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_IN_EP_0,
1713dc87e52SEdward Tomasz Napierala #else
1723dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
1733dc87e52SEdward Tomasz Napierala #endif
1743dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
1753dc87e52SEdward Tomasz Napierala };
1763dc87e52SEdward Tomasz Napierala 
1773dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc bulk_out_ep = {
1783dc87e52SEdward Tomasz Napierala 	.pPacketSize = &bulk_mps,
1793dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_OUT_EP_0
1803dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_OUT_EP_0,
1813dc87e52SEdward Tomasz Napierala #else
1823dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
1833dc87e52SEdward Tomasz Napierala #endif
1843dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
1853dc87e52SEdward Tomasz Napierala };
1863dc87e52SEdward Tomasz Napierala 
1873dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc intr_in_ep = {
1883dc87e52SEdward Tomasz Napierala 	.pPacketSize = &intr_mps,
1893dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
1903dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_INTERRUPT,
1913dc87e52SEdward Tomasz Napierala };
1923dc87e52SEdward Tomasz Napierala 
1933dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = {
1943dc87e52SEdward Tomasz Napierala 	&intr_in_ep,
1953dc87e52SEdward Tomasz Napierala 	NULL,
1963dc87e52SEdward Tomasz Napierala };
1973dc87e52SEdward Tomasz Napierala 
1983dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_control_interface = {
1993dc87e52SEdward Tomasz Napierala 	.ppEndpoints = eth_intr_endpoints,
2003dc87e52SEdward Tomasz Napierala 	.ppRawDesc = eth_control_if_desc,
2013dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC,
2023dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
2033dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_CDC_NONE,
2043dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_CONTROL_INDEX,
2053dc87e52SEdward Tomasz Napierala };
2063dc87e52SEdward Tomasz Napierala 
2073dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *eth_data_endpoints[] = {
2083dc87e52SEdward Tomasz Napierala 	&bulk_in_ep,
2093dc87e52SEdward Tomasz Napierala 	&bulk_out_ep,
2103dc87e52SEdward Tomasz Napierala 	NULL,
2113dc87e52SEdward Tomasz Napierala };
2123dc87e52SEdward Tomasz Napierala 
2133dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_data_null_interface = {
2143dc87e52SEdward Tomasz Napierala 	.ppEndpoints = NULL,		/* no endpoints */
2153dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
2163dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
2173dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
2183dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_DATA_INDEX,
2193dc87e52SEdward Tomasz Napierala };
2203dc87e52SEdward Tomasz Napierala 
2213dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_data_interface = {
2223dc87e52SEdward Tomasz Napierala 	.ppEndpoints = eth_data_endpoints,
2233dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
2243dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
2253dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
2263dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_DATA_INDEX,
2273dc87e52SEdward Tomasz Napierala 	.isAltInterface = 1,		/* this is an alternate setting */
2283dc87e52SEdward Tomasz Napierala };
2293dc87e52SEdward Tomasz Napierala 
2303dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size modem_bulk_mps = {
2313dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_LOW] = 8,
2323dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
2333dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
2343dc87e52SEdward Tomasz Napierala };
2353dc87e52SEdward Tomasz Napierala 
2363dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size modem_intr_mps = {
2373dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_LOW] = 8,
2383dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 8,
2393dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 8,
2403dc87e52SEdward Tomasz Napierala };
2413dc87e52SEdward Tomasz Napierala 
2423dc87e52SEdward Tomasz Napierala static const struct usb_temp_interval modem_intr_interval = {
2433dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_LOW] = 8,	/* 8ms */
2443dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_FULL] = 8,	/* 8ms */
2453dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_HIGH] = 7,	/* 8ms */
2463dc87e52SEdward Tomasz Napierala };
2473dc87e52SEdward Tomasz Napierala 
2483dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_0 = {
2493dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_intr_mps,
2503dc87e52SEdward Tomasz Napierala 	.pIntervals = &modem_intr_interval,
2513dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
2523dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_INTERRUPT,
2533dc87e52SEdward Tomasz Napierala };
2543dc87e52SEdward Tomasz Napierala 
2553dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_1 = {
2563dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_bulk_mps,
2573dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
2583dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
2593dc87e52SEdward Tomasz Napierala };
2603dc87e52SEdward Tomasz Napierala 
2613dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_2 = {
2623dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_bulk_mps,
2633dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
2643dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
2653dc87e52SEdward Tomasz Napierala };
2663dc87e52SEdward Tomasz Napierala 
2673dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = {
2683dc87e52SEdward Tomasz Napierala 	&modem_ep_0,
2693dc87e52SEdward Tomasz Napierala 	NULL,
2703dc87e52SEdward Tomasz Napierala };
2713dc87e52SEdward Tomasz Napierala 
2723dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = {
2733dc87e52SEdward Tomasz Napierala 	&modem_ep_1,
2743dc87e52SEdward Tomasz Napierala 	&modem_ep_2,
2753dc87e52SEdward Tomasz Napierala 	NULL,
2763dc87e52SEdward Tomasz Napierala };
2773dc87e52SEdward Tomasz Napierala 
2783dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_0[] = {
2793dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x00, 0x10, 0x01
2803dc87e52SEdward Tomasz Napierala };
2813dc87e52SEdward Tomasz Napierala 
2823dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_1[] = {
2833dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1
2843dc87e52SEdward Tomasz Napierala };
2853dc87e52SEdward Tomasz Napierala 
2863dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_2[] = {
2873dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1
2883dc87e52SEdward Tomasz Napierala };
2893dc87e52SEdward Tomasz Napierala 
2903dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_3[] = {
2913dc87e52SEdward Tomasz Napierala 	0x04, 0x24, 0x02, 0x07
2923dc87e52SEdward Tomasz Napierala };
2933dc87e52SEdward Tomasz Napierala 
2943dc87e52SEdward Tomasz Napierala static const void *modem_iface_0_desc[] = {
2953dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_0,
2963dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_1,
2973dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_2,
2983dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_3,
2993dc87e52SEdward Tomasz Napierala 	NULL,
3003dc87e52SEdward Tomasz Napierala };
3013dc87e52SEdward Tomasz Napierala 
3023dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc modem_iface_0 = {
3033dc87e52SEdward Tomasz Napierala 	.ppRawDesc = modem_iface_0_desc,
3043dc87e52SEdward Tomasz Napierala 	.ppEndpoints = modem_iface_0_ep,
3053dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC,
3063dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL,
3076b7e508cSEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_CDC_NONE,
3083dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_MODEM_INDEX,
3093dc87e52SEdward Tomasz Napierala };
3103dc87e52SEdward Tomasz Napierala 
3113dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc modem_iface_1 = {
3123dc87e52SEdward Tomasz Napierala 	.ppEndpoints = modem_iface_1_ep,
3133dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
3143dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
3153dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
3163dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_MODEM_INDEX,
3173dc87e52SEdward Tomasz Napierala };
3183dc87e52SEdward Tomasz Napierala 
3193dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size msc_bulk_mps = {
3203dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
3213dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
3223dc87e52SEdward Tomasz Napierala };
3233dc87e52SEdward Tomasz Napierala 
3243dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc msc_bulk_in_ep = {
3253dc87e52SEdward Tomasz Napierala 	.pPacketSize = &msc_bulk_mps,
3263dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_IN_EP_0
3273dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_IN_EP_0,
3283dc87e52SEdward Tomasz Napierala #else
3293dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
3303dc87e52SEdward Tomasz Napierala #endif
3313dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
3323dc87e52SEdward Tomasz Napierala };
3333dc87e52SEdward Tomasz Napierala 
3343dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc msc_bulk_out_ep = {
3353dc87e52SEdward Tomasz Napierala 	.pPacketSize = &msc_bulk_mps,
3363dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_OUT_EP_0
3373dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_OUT_EP_0,
3383dc87e52SEdward Tomasz Napierala #else
3393dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
3403dc87e52SEdward Tomasz Napierala #endif
3413dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
3423dc87e52SEdward Tomasz Napierala };
3433dc87e52SEdward Tomasz Napierala 
3443dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *msc_data_endpoints[] = {
3453dc87e52SEdward Tomasz Napierala 	&msc_bulk_in_ep,
3463dc87e52SEdward Tomasz Napierala 	&msc_bulk_out_ep,
3473dc87e52SEdward Tomasz Napierala 	NULL,
3483dc87e52SEdward Tomasz Napierala };
3493dc87e52SEdward Tomasz Napierala 
3503dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc msc_data_interface = {
3513dc87e52SEdward Tomasz Napierala 	.ppEndpoints = msc_data_endpoints,
3523dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_MASS,
3533dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_SCSI,
3543dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_MASS_BBB,
3553dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_STORAGE_INDEX,
3563dc87e52SEdward Tomasz Napierala };
3573dc87e52SEdward Tomasz Napierala 
3583dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc *multi_interfaces[] = {
3593dc87e52SEdward Tomasz Napierala 	&modem_iface_0,
3603dc87e52SEdward Tomasz Napierala 	&modem_iface_1,
3613dc87e52SEdward Tomasz Napierala 	&eth_control_interface,
3623dc87e52SEdward Tomasz Napierala 	&eth_data_null_interface,
3633dc87e52SEdward Tomasz Napierala 	&eth_data_interface,
3643dc87e52SEdward Tomasz Napierala 	&msc_data_interface,
3653dc87e52SEdward Tomasz Napierala 	NULL,
3663dc87e52SEdward Tomasz Napierala };
3673dc87e52SEdward Tomasz Napierala 
3683dc87e52SEdward Tomasz Napierala static const struct usb_temp_config_desc multi_config_desc = {
3693dc87e52SEdward Tomasz Napierala 	.ppIfaceDesc = multi_interfaces,
370d008c0d7SEdward Tomasz Napierala 	.bmAttributes = 0,
371d008c0d7SEdward Tomasz Napierala 	.bMaxPower = 0,
3723dc87e52SEdward Tomasz Napierala 	.iConfiguration = MULTI_CONFIGURATION_INDEX,
3733dc87e52SEdward Tomasz Napierala };
3743dc87e52SEdward Tomasz Napierala static const struct usb_temp_config_desc *multi_configs[] = {
3753dc87e52SEdward Tomasz Napierala 	&multi_config_desc,
3763dc87e52SEdward Tomasz Napierala 	NULL,
3773dc87e52SEdward Tomasz Napierala };
3783dc87e52SEdward Tomasz Napierala 
3793dc87e52SEdward Tomasz Napierala struct usb_temp_device_desc usb_template_multi = {
3803dc87e52SEdward Tomasz Napierala 	.getStringDesc = &multi_get_string_desc,
3813dc87e52SEdward Tomasz Napierala 	.ppConfigDesc = multi_configs,
3821558eec6SEdward Tomasz Napierala 	.idVendor = MULTI_DEFAULT_VENDOR_ID,
3831558eec6SEdward Tomasz Napierala 	.idProduct = MULTI_DEFAULT_PRODUCT_ID,
3843dc87e52SEdward Tomasz Napierala 	.bcdDevice = 0x0100,
3853dc87e52SEdward Tomasz Napierala 	.bDeviceClass = UDCLASS_IN_INTERFACE,
3863dc87e52SEdward Tomasz Napierala 	.bDeviceSubClass = 0,
3873dc87e52SEdward Tomasz Napierala 	.bDeviceProtocol = 0,
3883dc87e52SEdward Tomasz Napierala 	.iManufacturer = MULTI_MANUFACTURER_INDEX,
3893dc87e52SEdward Tomasz Napierala 	.iProduct = MULTI_PRODUCT_INDEX,
3903dc87e52SEdward Tomasz Napierala 	.iSerialNumber = MULTI_SERIAL_NUMBER_INDEX,
3913dc87e52SEdward Tomasz Napierala };
3923dc87e52SEdward Tomasz Napierala 
3933dc87e52SEdward Tomasz Napierala /*------------------------------------------------------------------------*
3943dc87e52SEdward Tomasz Napierala  *	multi_get_string_desc
3953dc87e52SEdward Tomasz Napierala  *
3963dc87e52SEdward Tomasz Napierala  * Return values:
3973dc87e52SEdward Tomasz Napierala  * NULL: Failure. No such string.
3983dc87e52SEdward Tomasz Napierala  * Else: Success. Pointer to string descriptor is returned.
3993dc87e52SEdward Tomasz Napierala  *------------------------------------------------------------------------*/
4003dc87e52SEdward Tomasz Napierala static const void *
multi_get_string_desc(uint16_t lang_id,uint8_t string_index)4013dc87e52SEdward Tomasz Napierala multi_get_string_desc(uint16_t lang_id, uint8_t string_index)
4023dc87e52SEdward Tomasz Napierala {
4033dc87e52SEdward Tomasz Napierala 	static const void *ptr[MULTI_MAX_INDEX] = {
4043dc87e52SEdward Tomasz Napierala 		[MULTI_LANG_INDEX] = &usb_string_lang_en,
4053dc87e52SEdward Tomasz Napierala 		[MULTI_MODEM_INDEX] = &multi_modem,
4063dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_MAC_INDEX] = &multi_eth_mac,
4073dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_CONTROL_INDEX] = &multi_eth_control,
4083dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_DATA_INDEX] = &multi_eth_data,
4093dc87e52SEdward Tomasz Napierala 		[MULTI_STORAGE_INDEX] = &multi_storage,
4103dc87e52SEdward Tomasz Napierala 		[MULTI_CONFIGURATION_INDEX] = &multi_configuration,
4113dc87e52SEdward Tomasz Napierala 		[MULTI_MANUFACTURER_INDEX] = &multi_manufacturer,
4123dc87e52SEdward Tomasz Napierala 		[MULTI_PRODUCT_INDEX] = &multi_product,
4133dc87e52SEdward Tomasz Napierala 		[MULTI_SERIAL_NUMBER_INDEX] = &multi_serial_number,
4143dc87e52SEdward Tomasz Napierala 	};
4153dc87e52SEdward Tomasz Napierala 
4163dc87e52SEdward Tomasz Napierala 	if (string_index == 0) {
4173dc87e52SEdward Tomasz Napierala 		return (&usb_string_lang_en);
4183dc87e52SEdward Tomasz Napierala 	}
4193dc87e52SEdward Tomasz Napierala 	if (lang_id != 0x0409) {
4203dc87e52SEdward Tomasz Napierala 		return (NULL);
4213dc87e52SEdward Tomasz Napierala 	}
4223dc87e52SEdward Tomasz Napierala 	if (string_index < MULTI_MAX_INDEX) {
4233dc87e52SEdward Tomasz Napierala 		return (ptr[string_index]);
4243dc87e52SEdward Tomasz Napierala 	}
4253dc87e52SEdward Tomasz Napierala 	return (NULL);
4263dc87e52SEdward Tomasz Napierala }
4273dc87e52SEdward Tomasz Napierala 
4283dc87e52SEdward Tomasz Napierala static void
multi_init(void * arg __unused)4293dc87e52SEdward Tomasz Napierala multi_init(void *arg __unused)
4303dc87e52SEdward Tomasz Napierala {
4313dc87e52SEdward Tomasz Napierala 	struct sysctl_oid *parent;
4323dc87e52SEdward Tomasz Napierala 	char parent_name[3];
4333dc87e52SEdward Tomasz Napierala 
4343dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_modem, sizeof(multi_modem),
4353dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_MODEM);
4363dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_mac, sizeof(multi_eth_mac),
4373dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_MAC);
4383dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_control, sizeof(multi_eth_control),
4393dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_CONTROL);
4403dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_data, sizeof(multi_eth_data),
4413dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_DATA);
4423dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_storage, sizeof(multi_storage),
4433dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_STORAGE);
4443dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_configuration, sizeof(multi_configuration),
4453dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_CONFIGURATION);
4463dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_manufacturer, sizeof(multi_manufacturer),
4473dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_MANUFACTURER);
4483dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_product, sizeof(multi_product),
4493dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_PRODUCT);
4503dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_serial_number, sizeof(multi_serial_number),
4513dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_SERIAL_NUMBER);
4523dc87e52SEdward Tomasz Napierala 
4533dc87e52SEdward Tomasz Napierala 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MULTI);
4543dc87e52SEdward Tomasz Napierala 	sysctl_ctx_init(&multi_ctx_list);
4553dc87e52SEdward Tomasz Napierala 
4563dc87e52SEdward Tomasz Napierala 	parent = SYSCTL_ADD_NODE(&multi_ctx_list,
4573dc87e52SEdward Tomasz Napierala 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
458f8d2b1f3SPawel Biernacki 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
4593dc87e52SEdward Tomasz Napierala 	    0, "USB Multifunction device side template");
4603dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_U16(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4613dc87e52SEdward Tomasz Napierala 	    "vendor_id", CTLFLAG_RWTUN,
4623dc87e52SEdward Tomasz Napierala 	    &usb_template_multi.idVendor, 1, "Vendor identifier");
4633dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_U16(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4643dc87e52SEdward Tomasz Napierala 	    "product_id", CTLFLAG_RWTUN,
4653dc87e52SEdward Tomasz Napierala 	    &usb_template_multi.idProduct, 1, "Product identifier");
4663dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4673dc87e52SEdward Tomasz Napierala 	    "eth_mac", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4683dc87e52SEdward Tomasz Napierala 	    &multi_eth_mac, sizeof(multi_eth_mac), usb_temp_sysctl,
4693dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet MAC address string");
4703dc87e52SEdward Tomasz Napierala #if 0
4713dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4723dc87e52SEdward Tomasz Napierala 	    "modem", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4733dc87e52SEdward Tomasz Napierala 	    &multi_modem, sizeof(multi_modem), usb_temp_sysctl,
4743dc87e52SEdward Tomasz Napierala 	    "A", "Modem interface string");
4753dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4763dc87e52SEdward Tomasz Napierala 	    "eth_control", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4773dc87e52SEdward Tomasz Napierala 	    &multi_eth_control, sizeof(multi_eth_data), usb_temp_sysctl,
4783dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet control interface string");
4793dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4803dc87e52SEdward Tomasz Napierala 	    "eth_data", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4813dc87e52SEdward Tomasz Napierala 	    &multi_eth_data, sizeof(multi_eth_data), usb_temp_sysctl,
4823dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet data interface string");
4833dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4843dc87e52SEdward Tomasz Napierala 	    "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4853dc87e52SEdward Tomasz Napierala 	    &multi_storage, sizeof(multi_storage), usb_temp_sysctl,
4863dc87e52SEdward Tomasz Napierala 	    "A", "Storage interface string");
4873dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4883dc87e52SEdward Tomasz Napierala 	    "configuration", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4893dc87e52SEdward Tomasz Napierala 	    &multi_configuration, sizeof(multi_configuration), usb_temp_sysctl,
4903dc87e52SEdward Tomasz Napierala 	    "A", "Configuration string");
4913dc87e52SEdward Tomasz Napierala #endif
4923dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4933dc87e52SEdward Tomasz Napierala 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4943dc87e52SEdward Tomasz Napierala 	    &multi_manufacturer, sizeof(multi_manufacturer), usb_temp_sysctl,
4953dc87e52SEdward Tomasz Napierala 	    "A", "Manufacturer string");
4963dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4973dc87e52SEdward Tomasz Napierala 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4983dc87e52SEdward Tomasz Napierala 	    &multi_product, sizeof(multi_product), usb_temp_sysctl,
4993dc87e52SEdward Tomasz Napierala 	    "A", "Product string");
5003dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
5013dc87e52SEdward Tomasz Napierala 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
5023dc87e52SEdward Tomasz Napierala 	    &multi_serial_number, sizeof(multi_serial_number), usb_temp_sysctl,
5033dc87e52SEdward Tomasz Napierala 	    "A", "Serial number string");
5043dc87e52SEdward Tomasz Napierala }
5053dc87e52SEdward Tomasz Napierala 
5063dc87e52SEdward Tomasz Napierala static void
multi_uninit(void * arg __unused)5073dc87e52SEdward Tomasz Napierala multi_uninit(void *arg __unused)
5083dc87e52SEdward Tomasz Napierala {
5093dc87e52SEdward Tomasz Napierala 
5103dc87e52SEdward Tomasz Napierala 	sysctl_ctx_free(&multi_ctx_list);
5113dc87e52SEdward Tomasz Napierala }
5123dc87e52SEdward Tomasz Napierala 
5133dc87e52SEdward Tomasz Napierala SYSINIT(multi_init, SI_SUB_LOCK, SI_ORDER_FIRST, multi_init, NULL);
5143dc87e52SEdward Tomasz Napierala SYSUNINIT(multi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, multi_uninit, NULL);
515