xref: /freebsd-src/sys/dev/usb/template/usb_template_multi.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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 #include <sys/cdefs.h>
413dc87e52SEdward Tomasz Napierala #ifdef USB_GLOBAL_INCLUDE_FILE
423dc87e52SEdward Tomasz Napierala #include USB_GLOBAL_INCLUDE_FILE
433dc87e52SEdward Tomasz Napierala #else
443dc87e52SEdward Tomasz Napierala #include <sys/stdint.h>
453dc87e52SEdward Tomasz Napierala #include <sys/stddef.h>
463dc87e52SEdward Tomasz Napierala #include <sys/param.h>
473dc87e52SEdward Tomasz Napierala #include <sys/queue.h>
483dc87e52SEdward Tomasz Napierala #include <sys/types.h>
493dc87e52SEdward Tomasz Napierala #include <sys/systm.h>
503dc87e52SEdward Tomasz Napierala #include <sys/kernel.h>
513dc87e52SEdward Tomasz Napierala #include <sys/bus.h>
523dc87e52SEdward Tomasz Napierala #include <sys/module.h>
533dc87e52SEdward Tomasz Napierala #include <sys/lock.h>
543dc87e52SEdward Tomasz Napierala #include <sys/mutex.h>
553dc87e52SEdward Tomasz Napierala #include <sys/condvar.h>
563dc87e52SEdward Tomasz Napierala #include <sys/sysctl.h>
573dc87e52SEdward Tomasz Napierala #include <sys/sx.h>
583dc87e52SEdward Tomasz Napierala #include <sys/unistd.h>
593dc87e52SEdward Tomasz Napierala #include <sys/callout.h>
603dc87e52SEdward Tomasz Napierala #include <sys/malloc.h>
613dc87e52SEdward Tomasz Napierala #include <sys/priv.h>
623dc87e52SEdward Tomasz Napierala 
633dc87e52SEdward Tomasz Napierala #include <dev/usb/usb.h>
643dc87e52SEdward Tomasz Napierala #include <dev/usb/usbdi.h>
653dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_core.h>
663dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_cdc.h>
673dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_ioctl.h>
683dc87e52SEdward Tomasz Napierala #include <dev/usb/usb_util.h>
693dc87e52SEdward Tomasz Napierala 
703dc87e52SEdward Tomasz Napierala #include <dev/usb/template/usb_template.h>
713dc87e52SEdward Tomasz Napierala #endif		/* USB_GLOBAL_INCLUDE_FILE */
723dc87e52SEdward Tomasz Napierala 
733dc87e52SEdward Tomasz Napierala #define	MODEM_IFACE_0 0
743dc87e52SEdward Tomasz Napierala #define	MODEM_IFACE_1 1
753dc87e52SEdward Tomasz Napierala 
763dc87e52SEdward Tomasz Napierala enum {
773dc87e52SEdward Tomasz Napierala 	MULTI_LANG_INDEX,
783dc87e52SEdward Tomasz Napierala 	MULTI_MODEM_INDEX,
793dc87e52SEdward Tomasz Napierala 	MULTI_ETH_MAC_INDEX,
803dc87e52SEdward Tomasz Napierala 	MULTI_ETH_CONTROL_INDEX,
813dc87e52SEdward Tomasz Napierala 	MULTI_ETH_DATA_INDEX,
823dc87e52SEdward Tomasz Napierala 	MULTI_STORAGE_INDEX,
833dc87e52SEdward Tomasz Napierala 	MULTI_CONFIGURATION_INDEX,
843dc87e52SEdward Tomasz Napierala 	MULTI_MANUFACTURER_INDEX,
853dc87e52SEdward Tomasz Napierala 	MULTI_PRODUCT_INDEX,
863dc87e52SEdward Tomasz Napierala 	MULTI_SERIAL_NUMBER_INDEX,
873dc87e52SEdward Tomasz Napierala 	MULTI_MAX_INDEX,
883dc87e52SEdward Tomasz Napierala };
893dc87e52SEdward Tomasz Napierala 
901558eec6SEdward Tomasz Napierala #define	MULTI_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
91d01c1c8bSEdward Tomasz Napierala #define	MULTI_DEFAULT_PRODUCT_ID	0x05dc
92ac4a7f30SEdward Tomasz Napierala #define	MULTI_DEFAULT_MODEM		"Virtual serial port"
933dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_MAC		"2A02030405060789AB"
943dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_CONTROL	"Ethernet Comm Interface"
953dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_ETH_DATA		"Ethernet Data Interface"
963dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_STORAGE		"Mass Storage Interface"
973dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_CONFIGURATION	"Default configuration"
98d01c1c8bSEdward Tomasz Napierala #define	MULTI_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
993dc87e52SEdward Tomasz Napierala #define	MULTI_DEFAULT_PRODUCT		"Multifunction Device"
100733efc21SEdward Tomasz Napierala /*
101733efc21SEdward Tomasz Napierala  * The reason for this being called like this is that OSX
102733efc21SEdward Tomasz Napierala  * derives the device node name from it, resulting in a somewhat
103733efc21SEdward Tomasz Napierala  * user-friendly "/dev/cu.usbmodemFreeBSD1".  And yes, the "1"
104733efc21SEdward Tomasz Napierala  * needs to be there, otherwise OSX will mangle it.
105733efc21SEdward Tomasz Napierala  */
106733efc21SEdward Tomasz Napierala #define MULTI_DEFAULT_SERIAL_NUMBER	"FreeBSD1"
1073dc87e52SEdward Tomasz Napierala 
1083dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_modem;
1093dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_mac;
1103dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_control;
1113dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_eth_data;
1123dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_storage;
1133dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_configuration;
1143dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_manufacturer;
1153dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_product;
1163dc87e52SEdward Tomasz Napierala static struct usb_string_descriptor	multi_serial_number;
1173dc87e52SEdward Tomasz Napierala 
1183dc87e52SEdward Tomasz Napierala static struct sysctl_ctx_list		multi_ctx_list;
1193dc87e52SEdward Tomasz Napierala 
1203dc87e52SEdward Tomasz Napierala /* prototypes */
1213dc87e52SEdward Tomasz Napierala 
1223dc87e52SEdward Tomasz Napierala static usb_temp_get_string_desc_t multi_get_string_desc;
1233dc87e52SEdward Tomasz Napierala 
1243dc87e52SEdward Tomasz Napierala static const struct usb_cdc_union_descriptor eth_union_desc = {
1253dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_union_desc),
1263dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1273dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_UNION,
1283dc87e52SEdward Tomasz Napierala 	.bMasterInterface = 0,		/* this is automatically updated */
1293dc87e52SEdward Tomasz Napierala 	.bSlaveInterface[0] = 1,	/* this is automatically updated */
1303dc87e52SEdward Tomasz Napierala };
1313dc87e52SEdward Tomasz Napierala 
1323dc87e52SEdward Tomasz Napierala static const struct usb_cdc_header_descriptor eth_header_desc = {
1333dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_header_desc),
1343dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1353dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_HEADER,
1363dc87e52SEdward Tomasz Napierala 	.bcdCDC[0] = 0x10,
1373dc87e52SEdward Tomasz Napierala 	.bcdCDC[1] = 0x01,
1383dc87e52SEdward Tomasz Napierala };
1393dc87e52SEdward Tomasz Napierala 
1403dc87e52SEdward Tomasz Napierala static const struct usb_cdc_ethernet_descriptor eth_enf_desc = {
1413dc87e52SEdward Tomasz Napierala 	.bLength = sizeof(eth_enf_desc),
1423dc87e52SEdward Tomasz Napierala 	.bDescriptorType = UDESC_CS_INTERFACE,
1433dc87e52SEdward Tomasz Napierala 	.bDescriptorSubtype = UDESCSUB_CDC_ENF,
1443dc87e52SEdward Tomasz Napierala 	.iMacAddress = MULTI_ETH_MAC_INDEX,
1453dc87e52SEdward Tomasz Napierala 	.bmEthernetStatistics = {0, 0, 0, 0},
1463dc87e52SEdward Tomasz Napierala 	.wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */
1473dc87e52SEdward Tomasz Napierala 	.wNumberMCFilters = {0, 0},
1483dc87e52SEdward Tomasz Napierala 	.bNumberPowerFilters = 0,
1493dc87e52SEdward Tomasz Napierala };
1503dc87e52SEdward Tomasz Napierala 
1513dc87e52SEdward Tomasz Napierala static const void *eth_control_if_desc[] = {
1523dc87e52SEdward Tomasz Napierala 	&eth_union_desc,
1533dc87e52SEdward Tomasz Napierala 	&eth_header_desc,
1543dc87e52SEdward Tomasz Napierala 	&eth_enf_desc,
1553dc87e52SEdward Tomasz Napierala 	NULL,
1563dc87e52SEdward Tomasz Napierala };
1573dc87e52SEdward Tomasz Napierala 
1583dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size bulk_mps = {
1593dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
1603dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
1613dc87e52SEdward Tomasz Napierala };
1623dc87e52SEdward Tomasz Napierala 
1633dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size intr_mps = {
1643dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 8,
1653dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 8,
1663dc87e52SEdward Tomasz Napierala };
1673dc87e52SEdward Tomasz Napierala 
1683dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc bulk_in_ep = {
1693dc87e52SEdward Tomasz Napierala 	.pPacketSize = &bulk_mps,
1703dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_IN_EP_0
1713dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_IN_EP_0,
1723dc87e52SEdward Tomasz Napierala #else
1733dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
1743dc87e52SEdward Tomasz Napierala #endif
1753dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
1763dc87e52SEdward Tomasz Napierala };
1773dc87e52SEdward Tomasz Napierala 
1783dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc bulk_out_ep = {
1793dc87e52SEdward Tomasz Napierala 	.pPacketSize = &bulk_mps,
1803dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_OUT_EP_0
1813dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_OUT_EP_0,
1823dc87e52SEdward Tomasz Napierala #else
1833dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
1843dc87e52SEdward Tomasz Napierala #endif
1853dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
1863dc87e52SEdward Tomasz Napierala };
1873dc87e52SEdward Tomasz Napierala 
1883dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc intr_in_ep = {
1893dc87e52SEdward Tomasz Napierala 	.pPacketSize = &intr_mps,
1903dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
1913dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_INTERRUPT,
1923dc87e52SEdward Tomasz Napierala };
1933dc87e52SEdward Tomasz Napierala 
1943dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = {
1953dc87e52SEdward Tomasz Napierala 	&intr_in_ep,
1963dc87e52SEdward Tomasz Napierala 	NULL,
1973dc87e52SEdward Tomasz Napierala };
1983dc87e52SEdward Tomasz Napierala 
1993dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_control_interface = {
2003dc87e52SEdward Tomasz Napierala 	.ppEndpoints = eth_intr_endpoints,
2013dc87e52SEdward Tomasz Napierala 	.ppRawDesc = eth_control_if_desc,
2023dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC,
2033dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
2043dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_CDC_NONE,
2053dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_CONTROL_INDEX,
2063dc87e52SEdward Tomasz Napierala };
2073dc87e52SEdward Tomasz Napierala 
2083dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *eth_data_endpoints[] = {
2093dc87e52SEdward Tomasz Napierala 	&bulk_in_ep,
2103dc87e52SEdward Tomasz Napierala 	&bulk_out_ep,
2113dc87e52SEdward Tomasz Napierala 	NULL,
2123dc87e52SEdward Tomasz Napierala };
2133dc87e52SEdward Tomasz Napierala 
2143dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_data_null_interface = {
2153dc87e52SEdward Tomasz Napierala 	.ppEndpoints = NULL,		/* no endpoints */
2163dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
2173dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
2183dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
2193dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_DATA_INDEX,
2203dc87e52SEdward Tomasz Napierala };
2213dc87e52SEdward Tomasz Napierala 
2223dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc eth_data_interface = {
2233dc87e52SEdward Tomasz Napierala 	.ppEndpoints = eth_data_endpoints,
2243dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
2253dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
2263dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
2273dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_ETH_DATA_INDEX,
2283dc87e52SEdward Tomasz Napierala 	.isAltInterface = 1,		/* this is an alternate setting */
2293dc87e52SEdward Tomasz Napierala };
2303dc87e52SEdward Tomasz Napierala 
2313dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size modem_bulk_mps = {
2323dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_LOW] = 8,
2333dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
2343dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
2353dc87e52SEdward Tomasz Napierala };
2363dc87e52SEdward Tomasz Napierala 
2373dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size modem_intr_mps = {
2383dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_LOW] = 8,
2393dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 8,
2403dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 8,
2413dc87e52SEdward Tomasz Napierala };
2423dc87e52SEdward Tomasz Napierala 
2433dc87e52SEdward Tomasz Napierala static const struct usb_temp_interval modem_intr_interval = {
2443dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_LOW] = 8,	/* 8ms */
2453dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_FULL] = 8,	/* 8ms */
2463dc87e52SEdward Tomasz Napierala 	.bInterval[USB_SPEED_HIGH] = 7,	/* 8ms */
2473dc87e52SEdward Tomasz Napierala };
2483dc87e52SEdward Tomasz Napierala 
2493dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_0 = {
2503dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_intr_mps,
2513dc87e52SEdward Tomasz Napierala 	.pIntervals = &modem_intr_interval,
2523dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
2533dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_INTERRUPT,
2543dc87e52SEdward Tomasz Napierala };
2553dc87e52SEdward Tomasz Napierala 
2563dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_1 = {
2573dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_bulk_mps,
2583dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
2593dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
2603dc87e52SEdward Tomasz Napierala };
2613dc87e52SEdward Tomasz Napierala 
2623dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc modem_ep_2 = {
2633dc87e52SEdward Tomasz Napierala 	.pPacketSize = &modem_bulk_mps,
2643dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
2653dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
2663dc87e52SEdward Tomasz Napierala };
2673dc87e52SEdward Tomasz Napierala 
2683dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = {
2693dc87e52SEdward Tomasz Napierala 	&modem_ep_0,
2703dc87e52SEdward Tomasz Napierala 	NULL,
2713dc87e52SEdward Tomasz Napierala };
2723dc87e52SEdward Tomasz Napierala 
2733dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = {
2743dc87e52SEdward Tomasz Napierala 	&modem_ep_1,
2753dc87e52SEdward Tomasz Napierala 	&modem_ep_2,
2763dc87e52SEdward Tomasz Napierala 	NULL,
2773dc87e52SEdward Tomasz Napierala };
2783dc87e52SEdward Tomasz Napierala 
2793dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_0[] = {
2803dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x00, 0x10, 0x01
2813dc87e52SEdward Tomasz Napierala };
2823dc87e52SEdward Tomasz Napierala 
2833dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_1[] = {
2843dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1
2853dc87e52SEdward Tomasz Napierala };
2863dc87e52SEdward Tomasz Napierala 
2873dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_2[] = {
2883dc87e52SEdward Tomasz Napierala 	0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1
2893dc87e52SEdward Tomasz Napierala };
2903dc87e52SEdward Tomasz Napierala 
2913dc87e52SEdward Tomasz Napierala static const uint8_t modem_raw_desc_3[] = {
2923dc87e52SEdward Tomasz Napierala 	0x04, 0x24, 0x02, 0x07
2933dc87e52SEdward Tomasz Napierala };
2943dc87e52SEdward Tomasz Napierala 
2953dc87e52SEdward Tomasz Napierala static const void *modem_iface_0_desc[] = {
2963dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_0,
2973dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_1,
2983dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_2,
2993dc87e52SEdward Tomasz Napierala 	&modem_raw_desc_3,
3003dc87e52SEdward Tomasz Napierala 	NULL,
3013dc87e52SEdward Tomasz Napierala };
3023dc87e52SEdward Tomasz Napierala 
3033dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc modem_iface_0 = {
3043dc87e52SEdward Tomasz Napierala 	.ppRawDesc = modem_iface_0_desc,
3053dc87e52SEdward Tomasz Napierala 	.ppEndpoints = modem_iface_0_ep,
3063dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC,
3073dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL,
3086b7e508cSEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_CDC_NONE,
3093dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_MODEM_INDEX,
3103dc87e52SEdward Tomasz Napierala };
3113dc87e52SEdward Tomasz Napierala 
3123dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc modem_iface_1 = {
3133dc87e52SEdward Tomasz Napierala 	.ppEndpoints = modem_iface_1_ep,
3143dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_CDC_DATA,
3153dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_DATA,
3163dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = 0,
3173dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_MODEM_INDEX,
3183dc87e52SEdward Tomasz Napierala };
3193dc87e52SEdward Tomasz Napierala 
3203dc87e52SEdward Tomasz Napierala static const struct usb_temp_packet_size msc_bulk_mps = {
3213dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_FULL] = 64,
3223dc87e52SEdward Tomasz Napierala 	.mps[USB_SPEED_HIGH] = 512,
3233dc87e52SEdward Tomasz Napierala };
3243dc87e52SEdward Tomasz Napierala 
3253dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc msc_bulk_in_ep = {
3263dc87e52SEdward Tomasz Napierala 	.pPacketSize = &msc_bulk_mps,
3273dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_IN_EP_0
3283dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_IN_EP_0,
3293dc87e52SEdward Tomasz Napierala #else
3303dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_IN,
3313dc87e52SEdward Tomasz Napierala #endif
3323dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
3333dc87e52SEdward Tomasz Napierala };
3343dc87e52SEdward Tomasz Napierala 
3353dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc msc_bulk_out_ep = {
3363dc87e52SEdward Tomasz Napierala 	.pPacketSize = &msc_bulk_mps,
3373dc87e52SEdward Tomasz Napierala #ifdef USB_HIP_OUT_EP_0
3383dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = USB_HIP_OUT_EP_0,
3393dc87e52SEdward Tomasz Napierala #else
3403dc87e52SEdward Tomasz Napierala 	.bEndpointAddress = UE_DIR_OUT,
3413dc87e52SEdward Tomasz Napierala #endif
3423dc87e52SEdward Tomasz Napierala 	.bmAttributes = UE_BULK,
3433dc87e52SEdward Tomasz Napierala };
3443dc87e52SEdward Tomasz Napierala 
3453dc87e52SEdward Tomasz Napierala static const struct usb_temp_endpoint_desc *msc_data_endpoints[] = {
3463dc87e52SEdward Tomasz Napierala 	&msc_bulk_in_ep,
3473dc87e52SEdward Tomasz Napierala 	&msc_bulk_out_ep,
3483dc87e52SEdward Tomasz Napierala 	NULL,
3493dc87e52SEdward Tomasz Napierala };
3503dc87e52SEdward Tomasz Napierala 
3513dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc msc_data_interface = {
3523dc87e52SEdward Tomasz Napierala 	.ppEndpoints = msc_data_endpoints,
3533dc87e52SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_MASS,
3543dc87e52SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_SCSI,
3553dc87e52SEdward Tomasz Napierala 	.bInterfaceProtocol = UIPROTO_MASS_BBB,
3563dc87e52SEdward Tomasz Napierala 	.iInterface = MULTI_STORAGE_INDEX,
3573dc87e52SEdward Tomasz Napierala };
3583dc87e52SEdward Tomasz Napierala 
3593dc87e52SEdward Tomasz Napierala static const struct usb_temp_interface_desc *multi_interfaces[] = {
3603dc87e52SEdward Tomasz Napierala 	&modem_iface_0,
3613dc87e52SEdward Tomasz Napierala 	&modem_iface_1,
3623dc87e52SEdward Tomasz Napierala 	&eth_control_interface,
3633dc87e52SEdward Tomasz Napierala 	&eth_data_null_interface,
3643dc87e52SEdward Tomasz Napierala 	&eth_data_interface,
3653dc87e52SEdward Tomasz Napierala 	&msc_data_interface,
3663dc87e52SEdward Tomasz Napierala 	NULL,
3673dc87e52SEdward Tomasz Napierala };
3683dc87e52SEdward Tomasz Napierala 
3693dc87e52SEdward Tomasz Napierala static const struct usb_temp_config_desc multi_config_desc = {
3703dc87e52SEdward Tomasz Napierala 	.ppIfaceDesc = multi_interfaces,
371d008c0d7SEdward Tomasz Napierala 	.bmAttributes = 0,
372d008c0d7SEdward Tomasz Napierala 	.bMaxPower = 0,
3733dc87e52SEdward Tomasz Napierala 	.iConfiguration = MULTI_CONFIGURATION_INDEX,
3743dc87e52SEdward Tomasz Napierala };
3753dc87e52SEdward Tomasz Napierala static const struct usb_temp_config_desc *multi_configs[] = {
3763dc87e52SEdward Tomasz Napierala 	&multi_config_desc,
3773dc87e52SEdward Tomasz Napierala 	NULL,
3783dc87e52SEdward Tomasz Napierala };
3793dc87e52SEdward Tomasz Napierala 
3803dc87e52SEdward Tomasz Napierala struct usb_temp_device_desc usb_template_multi = {
3813dc87e52SEdward Tomasz Napierala 	.getStringDesc = &multi_get_string_desc,
3823dc87e52SEdward Tomasz Napierala 	.ppConfigDesc = multi_configs,
3831558eec6SEdward Tomasz Napierala 	.idVendor = MULTI_DEFAULT_VENDOR_ID,
3841558eec6SEdward Tomasz Napierala 	.idProduct = MULTI_DEFAULT_PRODUCT_ID,
3853dc87e52SEdward Tomasz Napierala 	.bcdDevice = 0x0100,
3863dc87e52SEdward Tomasz Napierala 	.bDeviceClass = UDCLASS_IN_INTERFACE,
3873dc87e52SEdward Tomasz Napierala 	.bDeviceSubClass = 0,
3883dc87e52SEdward Tomasz Napierala 	.bDeviceProtocol = 0,
3893dc87e52SEdward Tomasz Napierala 	.iManufacturer = MULTI_MANUFACTURER_INDEX,
3903dc87e52SEdward Tomasz Napierala 	.iProduct = MULTI_PRODUCT_INDEX,
3913dc87e52SEdward Tomasz Napierala 	.iSerialNumber = MULTI_SERIAL_NUMBER_INDEX,
3923dc87e52SEdward Tomasz Napierala };
3933dc87e52SEdward Tomasz Napierala 
3943dc87e52SEdward Tomasz Napierala /*------------------------------------------------------------------------*
3953dc87e52SEdward Tomasz Napierala  *	multi_get_string_desc
3963dc87e52SEdward Tomasz Napierala  *
3973dc87e52SEdward Tomasz Napierala  * Return values:
3983dc87e52SEdward Tomasz Napierala  * NULL: Failure. No such string.
3993dc87e52SEdward Tomasz Napierala  * Else: Success. Pointer to string descriptor is returned.
4003dc87e52SEdward Tomasz Napierala  *------------------------------------------------------------------------*/
4013dc87e52SEdward Tomasz Napierala static const void *
multi_get_string_desc(uint16_t lang_id,uint8_t string_index)4023dc87e52SEdward Tomasz Napierala multi_get_string_desc(uint16_t lang_id, uint8_t string_index)
4033dc87e52SEdward Tomasz Napierala {
4043dc87e52SEdward Tomasz Napierala 	static const void *ptr[MULTI_MAX_INDEX] = {
4053dc87e52SEdward Tomasz Napierala 		[MULTI_LANG_INDEX] = &usb_string_lang_en,
4063dc87e52SEdward Tomasz Napierala 		[MULTI_MODEM_INDEX] = &multi_modem,
4073dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_MAC_INDEX] = &multi_eth_mac,
4083dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_CONTROL_INDEX] = &multi_eth_control,
4093dc87e52SEdward Tomasz Napierala 		[MULTI_ETH_DATA_INDEX] = &multi_eth_data,
4103dc87e52SEdward Tomasz Napierala 		[MULTI_STORAGE_INDEX] = &multi_storage,
4113dc87e52SEdward Tomasz Napierala 		[MULTI_CONFIGURATION_INDEX] = &multi_configuration,
4123dc87e52SEdward Tomasz Napierala 		[MULTI_MANUFACTURER_INDEX] = &multi_manufacturer,
4133dc87e52SEdward Tomasz Napierala 		[MULTI_PRODUCT_INDEX] = &multi_product,
4143dc87e52SEdward Tomasz Napierala 		[MULTI_SERIAL_NUMBER_INDEX] = &multi_serial_number,
4153dc87e52SEdward Tomasz Napierala 	};
4163dc87e52SEdward Tomasz Napierala 
4173dc87e52SEdward Tomasz Napierala 	if (string_index == 0) {
4183dc87e52SEdward Tomasz Napierala 		return (&usb_string_lang_en);
4193dc87e52SEdward Tomasz Napierala 	}
4203dc87e52SEdward Tomasz Napierala 	if (lang_id != 0x0409) {
4213dc87e52SEdward Tomasz Napierala 		return (NULL);
4223dc87e52SEdward Tomasz Napierala 	}
4233dc87e52SEdward Tomasz Napierala 	if (string_index < MULTI_MAX_INDEX) {
4243dc87e52SEdward Tomasz Napierala 		return (ptr[string_index]);
4253dc87e52SEdward Tomasz Napierala 	}
4263dc87e52SEdward Tomasz Napierala 	return (NULL);
4273dc87e52SEdward Tomasz Napierala }
4283dc87e52SEdward Tomasz Napierala 
4293dc87e52SEdward Tomasz Napierala static void
multi_init(void * arg __unused)4303dc87e52SEdward Tomasz Napierala multi_init(void *arg __unused)
4313dc87e52SEdward Tomasz Napierala {
4323dc87e52SEdward Tomasz Napierala 	struct sysctl_oid *parent;
4333dc87e52SEdward Tomasz Napierala 	char parent_name[3];
4343dc87e52SEdward Tomasz Napierala 
4353dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_modem, sizeof(multi_modem),
4363dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_MODEM);
4373dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_mac, sizeof(multi_eth_mac),
4383dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_MAC);
4393dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_control, sizeof(multi_eth_control),
4403dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_CONTROL);
4413dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_eth_data, sizeof(multi_eth_data),
4423dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_ETH_DATA);
4433dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_storage, sizeof(multi_storage),
4443dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_STORAGE);
4453dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_configuration, sizeof(multi_configuration),
4463dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_CONFIGURATION);
4473dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_manufacturer, sizeof(multi_manufacturer),
4483dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_MANUFACTURER);
4493dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_product, sizeof(multi_product),
4503dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_PRODUCT);
4513dc87e52SEdward Tomasz Napierala 	usb_make_str_desc(&multi_serial_number, sizeof(multi_serial_number),
4523dc87e52SEdward Tomasz Napierala 	    MULTI_DEFAULT_SERIAL_NUMBER);
4533dc87e52SEdward Tomasz Napierala 
4543dc87e52SEdward Tomasz Napierala 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MULTI);
4553dc87e52SEdward Tomasz Napierala 	sysctl_ctx_init(&multi_ctx_list);
4563dc87e52SEdward Tomasz Napierala 
4573dc87e52SEdward Tomasz Napierala 	parent = SYSCTL_ADD_NODE(&multi_ctx_list,
4583dc87e52SEdward Tomasz Napierala 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
459f8d2b1f3SPawel Biernacki 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
4603dc87e52SEdward Tomasz Napierala 	    0, "USB Multifunction device side template");
4613dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_U16(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4623dc87e52SEdward Tomasz Napierala 	    "vendor_id", CTLFLAG_RWTUN,
4633dc87e52SEdward Tomasz Napierala 	    &usb_template_multi.idVendor, 1, "Vendor identifier");
4643dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_U16(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4653dc87e52SEdward Tomasz Napierala 	    "product_id", CTLFLAG_RWTUN,
4663dc87e52SEdward Tomasz Napierala 	    &usb_template_multi.idProduct, 1, "Product identifier");
4673dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4683dc87e52SEdward Tomasz Napierala 	    "eth_mac", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4693dc87e52SEdward Tomasz Napierala 	    &multi_eth_mac, sizeof(multi_eth_mac), usb_temp_sysctl,
4703dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet MAC address string");
4713dc87e52SEdward Tomasz Napierala #if 0
4723dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4733dc87e52SEdward Tomasz Napierala 	    "modem", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4743dc87e52SEdward Tomasz Napierala 	    &multi_modem, sizeof(multi_modem), usb_temp_sysctl,
4753dc87e52SEdward Tomasz Napierala 	    "A", "Modem interface string");
4763dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4773dc87e52SEdward Tomasz Napierala 	    "eth_control", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4783dc87e52SEdward Tomasz Napierala 	    &multi_eth_control, sizeof(multi_eth_data), usb_temp_sysctl,
4793dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet control interface string");
4803dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4813dc87e52SEdward Tomasz Napierala 	    "eth_data", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4823dc87e52SEdward Tomasz Napierala 	    &multi_eth_data, sizeof(multi_eth_data), usb_temp_sysctl,
4833dc87e52SEdward Tomasz Napierala 	    "A", "Ethernet data interface string");
4843dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4853dc87e52SEdward Tomasz Napierala 	    "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4863dc87e52SEdward Tomasz Napierala 	    &multi_storage, sizeof(multi_storage), usb_temp_sysctl,
4873dc87e52SEdward Tomasz Napierala 	    "A", "Storage interface string");
4883dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4893dc87e52SEdward Tomasz Napierala 	    "configuration", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4903dc87e52SEdward Tomasz Napierala 	    &multi_configuration, sizeof(multi_configuration), usb_temp_sysctl,
4913dc87e52SEdward Tomasz Napierala 	    "A", "Configuration string");
4923dc87e52SEdward Tomasz Napierala #endif
4933dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4943dc87e52SEdward Tomasz Napierala 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4953dc87e52SEdward Tomasz Napierala 	    &multi_manufacturer, sizeof(multi_manufacturer), usb_temp_sysctl,
4963dc87e52SEdward Tomasz Napierala 	    "A", "Manufacturer string");
4973dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4983dc87e52SEdward Tomasz Napierala 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4993dc87e52SEdward Tomasz Napierala 	    &multi_product, sizeof(multi_product), usb_temp_sysctl,
5003dc87e52SEdward Tomasz Napierala 	    "A", "Product string");
5013dc87e52SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&multi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
5023dc87e52SEdward Tomasz Napierala 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
5033dc87e52SEdward Tomasz Napierala 	    &multi_serial_number, sizeof(multi_serial_number), usb_temp_sysctl,
5043dc87e52SEdward Tomasz Napierala 	    "A", "Serial number string");
5053dc87e52SEdward Tomasz Napierala }
5063dc87e52SEdward Tomasz Napierala 
5073dc87e52SEdward Tomasz Napierala static void
multi_uninit(void * arg __unused)5083dc87e52SEdward Tomasz Napierala multi_uninit(void *arg __unused)
5093dc87e52SEdward Tomasz Napierala {
5103dc87e52SEdward Tomasz Napierala 
5113dc87e52SEdward Tomasz Napierala 	sysctl_ctx_free(&multi_ctx_list);
5123dc87e52SEdward Tomasz Napierala }
5133dc87e52SEdward Tomasz Napierala 
5143dc87e52SEdward Tomasz Napierala SYSINIT(multi_init, SI_SUB_LOCK, SI_ORDER_FIRST, multi_init, NULL);
5153dc87e52SEdward Tomasz Napierala SYSUNINIT(multi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, multi_uninit, NULL);
516