xref: /freebsd/sys/dev/usb/template/usb_template_cdce.c (revision ce6a89e27cd190313be39bb479880aeda4778436)
1 /* $FreeBSD$ */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2007 Hans Petter Selasky <hselasky@FreeBSD.org>
6  * Copyright (c) 2018 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Edward Tomasz Napierala
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * This file contains the USB templates for a CDC USB ethernet device.
36  */
37 
38 #ifdef USB_GLOBAL_INCLUDE_FILE
39 #include USB_GLOBAL_INCLUDE_FILE
40 #else
41 #include <sys/stdint.h>
42 #include <sys/stddef.h>
43 #include <sys/param.h>
44 #include <sys/queue.h>
45 #include <sys/types.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/bus.h>
49 #include <sys/module.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/condvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/sx.h>
55 #include <sys/unistd.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
58 #include <sys/priv.h>
59 
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usb_core.h>
63 #include <dev/usb/usb_cdc.h>
64 #include <dev/usb/usb_ioctl.h>
65 #include <dev/usb/usb_util.h>
66 
67 #include <dev/usb/template/usb_template.h>
68 #endif			/* USB_GLOBAL_INCLUDE_FILE */
69 
70 enum {
71 	ETH_LANG_INDEX,
72 	ETH_MAC_INDEX,
73 	ETH_CONTROL_INDEX,
74 	ETH_DATA_INDEX,
75 	ETH_CONFIGURATION_INDEX,
76 	ETH_MANUFACTURER_INDEX,
77 	ETH_PRODUCT_INDEX,
78 	ETH_SERIAL_NUMBER_INDEX,
79 	ETH_MAX_INDEX,
80 };
81 
82 #define	ETH_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
83 #define	ETH_DEFAULT_PRODUCT_ID		0x27e1
84 #define	ETH_DEFAULT_MAC			"2A02030405060789AB"
85 #define	ETH_DEFAULT_CONTROL		"USB Ethernet Comm Interface"
86 #define	ETH_DEFAULT_DATA		"USB Ethernet Data Interface"
87 #define	ETH_DEFAULT_CONFIG		"Default Config"
88 #define	ETH_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
89 #define	ETH_DEFAULT_PRODUCT		"USB Ethernet Adapter"
90 #define	ETH_DEFAULT_SERIAL_NUMBER	"December 2007"
91 
92 static struct usb_string_descriptor	eth_mac;
93 static struct usb_string_descriptor	eth_control;
94 static struct usb_string_descriptor	eth_data;
95 static struct usb_string_descriptor	eth_configuration;
96 static struct usb_string_descriptor	eth_manufacturer;
97 static struct usb_string_descriptor	eth_product;
98 static struct usb_string_descriptor	eth_serial_number;
99 
100 static struct sysctl_ctx_list		eth_ctx_list;
101 
102 /* prototypes */
103 
104 static usb_temp_get_string_desc_t eth_get_string_desc;
105 
106 static const struct usb_cdc_union_descriptor eth_union_desc = {
107 	.bLength = sizeof(eth_union_desc),
108 	.bDescriptorType = UDESC_CS_INTERFACE,
109 	.bDescriptorSubtype = UDESCSUB_CDC_UNION,
110 	.bMasterInterface = 0,		/* this is automatically updated */
111 	.bSlaveInterface[0] = 1,	/* this is automatically updated */
112 };
113 
114 static const struct usb_cdc_header_descriptor eth_header_desc = {
115 	.bLength = sizeof(eth_header_desc),
116 	.bDescriptorType = UDESC_CS_INTERFACE,
117 	.bDescriptorSubtype = UDESCSUB_CDC_HEADER,
118 	.bcdCDC[0] = 0x10,
119 	.bcdCDC[1] = 0x01,
120 };
121 
122 static const struct usb_cdc_ethernet_descriptor eth_enf_desc = {
123 	.bLength = sizeof(eth_enf_desc),
124 	.bDescriptorType = UDESC_CS_INTERFACE,
125 	.bDescriptorSubtype = UDESCSUB_CDC_ENF,
126 	.iMacAddress = ETH_MAC_INDEX,
127 	.bmEthernetStatistics = {0, 0, 0, 0},
128 	.wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */
129 	.wNumberMCFilters = {0, 0},
130 	.bNumberPowerFilters = 0,
131 };
132 
133 static const void *eth_control_if_desc[] = {
134 	&eth_union_desc,
135 	&eth_header_desc,
136 	&eth_enf_desc,
137 	NULL,
138 };
139 
140 static const struct usb_temp_packet_size bulk_mps = {
141 	.mps[USB_SPEED_FULL] = 64,
142 	.mps[USB_SPEED_HIGH] = 512,
143 };
144 
145 static const struct usb_temp_packet_size intr_mps = {
146 	.mps[USB_SPEED_FULL] = 8,
147 	.mps[USB_SPEED_HIGH] = 8,
148 };
149 
150 static const struct usb_temp_endpoint_desc bulk_in_ep = {
151 	.pPacketSize = &bulk_mps,
152 #ifdef USB_HIP_IN_EP_0
153 	.bEndpointAddress = USB_HIP_IN_EP_0,
154 #else
155 	.bEndpointAddress = UE_DIR_IN,
156 #endif
157 	.bmAttributes = UE_BULK,
158 };
159 
160 static const struct usb_temp_endpoint_desc bulk_out_ep = {
161 	.pPacketSize = &bulk_mps,
162 #ifdef USB_HIP_OUT_EP_0
163 	.bEndpointAddress = USB_HIP_OUT_EP_0,
164 #else
165 	.bEndpointAddress = UE_DIR_OUT,
166 #endif
167 	.bmAttributes = UE_BULK,
168 };
169 
170 static const struct usb_temp_endpoint_desc intr_in_ep = {
171 	.pPacketSize = &intr_mps,
172 	.bEndpointAddress = UE_DIR_IN,
173 	.bmAttributes = UE_INTERRUPT,
174 };
175 
176 static const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = {
177 	&intr_in_ep,
178 	NULL,
179 };
180 
181 static const struct usb_temp_interface_desc eth_control_interface = {
182 	.ppEndpoints = eth_intr_endpoints,
183 	.ppRawDesc = eth_control_if_desc,
184 	.bInterfaceClass = UICLASS_CDC,
185 	.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
186 	.bInterfaceProtocol = 0,
187 	.iInterface = ETH_CONTROL_INDEX,
188 };
189 
190 static const struct usb_temp_endpoint_desc *eth_data_endpoints[] = {
191 	&bulk_in_ep,
192 	&bulk_out_ep,
193 	NULL,
194 };
195 
196 static const struct usb_temp_interface_desc eth_data_null_interface = {
197 	.ppEndpoints = NULL,		/* no endpoints */
198 	.bInterfaceClass = UICLASS_CDC_DATA,
199 	.bInterfaceSubClass = 0,
200 	.bInterfaceProtocol = 0,
201 	.iInterface = ETH_DATA_INDEX,
202 };
203 
204 static const struct usb_temp_interface_desc eth_data_interface = {
205 	.ppEndpoints = eth_data_endpoints,
206 	.bInterfaceClass = UICLASS_CDC_DATA,
207 	.bInterfaceSubClass = UISUBCLASS_DATA,
208 	.bInterfaceProtocol = 0,
209 	.iInterface = ETH_DATA_INDEX,
210 	.isAltInterface = 1,		/* this is an alternate setting */
211 };
212 
213 static const struct usb_temp_interface_desc *eth_interfaces[] = {
214 	&eth_control_interface,
215 	&eth_data_null_interface,
216 	&eth_data_interface,
217 	NULL,
218 };
219 
220 static const struct usb_temp_config_desc eth_config_desc = {
221 	.ppIfaceDesc = eth_interfaces,
222 	.bmAttributes = 0,
223 	.bMaxPower = 0,
224 	.iConfiguration = ETH_CONFIGURATION_INDEX,
225 };
226 
227 static const struct usb_temp_config_desc *eth_configs[] = {
228 	&eth_config_desc,
229 	NULL,
230 };
231 
232 struct usb_temp_device_desc usb_template_cdce = {
233 	.getStringDesc = &eth_get_string_desc,
234 	.ppConfigDesc = eth_configs,
235 	.idVendor = ETH_DEFAULT_VENDOR_ID,
236 	.idProduct = ETH_DEFAULT_PRODUCT_ID,
237 	.bcdDevice = 0x0100,
238 	.bDeviceClass = UDCLASS_COMM,
239 	.bDeviceSubClass = 0,
240 	.bDeviceProtocol = 0,
241 	.iManufacturer = ETH_MANUFACTURER_INDEX,
242 	.iProduct = ETH_PRODUCT_INDEX,
243 	.iSerialNumber = ETH_SERIAL_NUMBER_INDEX,
244 };
245 
246 /*------------------------------------------------------------------------*
247  *	eth_get_string_desc
248  *
249  * Return values:
250  * NULL: Failure. No such string.
251  * Else: Success. Pointer to string descriptor is returned.
252  *------------------------------------------------------------------------*/
253 static const void *
254 eth_get_string_desc(uint16_t lang_id, uint8_t string_index)
255 {
256 	static const void *ptr[ETH_MAX_INDEX] = {
257 		[ETH_LANG_INDEX] = &usb_string_lang_en,
258 		[ETH_MAC_INDEX] = &eth_mac,
259 		[ETH_CONTROL_INDEX] = &eth_control,
260 		[ETH_DATA_INDEX] = &eth_data,
261 		[ETH_CONFIGURATION_INDEX] = &eth_configuration,
262 		[ETH_MANUFACTURER_INDEX] = &eth_manufacturer,
263 		[ETH_PRODUCT_INDEX] = &eth_product,
264 		[ETH_SERIAL_NUMBER_INDEX] = &eth_serial_number,
265 	};
266 
267 	if (string_index == 0) {
268 		return (&usb_string_lang_en);
269 	}
270 	if (lang_id != 0x0409) {
271 		return (NULL);
272 	}
273 	if (string_index < ETH_MAX_INDEX) {
274 		return (ptr[string_index]);
275 	}
276 	return (NULL);
277 }
278 
279 static void
280 eth_init(void *arg __unused)
281 {
282 	struct sysctl_oid *parent;
283 	char parent_name[3];
284 
285 	usb_make_str_desc(&eth_mac, sizeof(eth_mac),
286 	    ETH_DEFAULT_MAC);
287 	usb_make_str_desc(&eth_control, sizeof(eth_control),
288 	    ETH_DEFAULT_CONTROL);
289 	usb_make_str_desc(&eth_data, sizeof(eth_data),
290 	    ETH_DEFAULT_DATA);
291 	usb_make_str_desc(&eth_configuration, sizeof(eth_configuration),
292 	    ETH_DEFAULT_CONFIG);
293 	usb_make_str_desc(&eth_manufacturer, sizeof(eth_manufacturer),
294 	    ETH_DEFAULT_MANUFACTURER);
295 	usb_make_str_desc(&eth_product, sizeof(eth_product),
296 	    ETH_DEFAULT_PRODUCT);
297 	usb_make_str_desc(&eth_serial_number, sizeof(eth_serial_number),
298 	    ETH_DEFAULT_SERIAL_NUMBER);
299 
300 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_CDCE);
301 	sysctl_ctx_init(&eth_ctx_list);
302 
303 	parent = SYSCTL_ADD_NODE(&eth_ctx_list,
304 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
305 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
306 	    0, "USB CDC Ethernet device side template");
307 	SYSCTL_ADD_U16(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
308 	    "vendor_id", CTLFLAG_RWTUN,
309 	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
310 	SYSCTL_ADD_U16(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
311 	    "product_id", CTLFLAG_RWTUN,
312 	    &usb_template_cdce.idProduct, 1, "Product identifier");
313 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
314 	    "mac", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
315 	    &eth_mac, sizeof(eth_mac), usb_temp_sysctl,
316 	    "A", "MAC address string");
317 #if 0
318 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
319 	    "control", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
320 	    &eth_control, sizeof(eth_control), usb_temp_sysctl,
321 	    "A", "Control interface string");
322 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
323 	    "data", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
324 	    &eth_data, sizeof(eth_data), usb_temp_sysctl,
325 	    "A", "Data interface string");
326 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
327 	    "configuration", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
328 	    &eth_configuration, sizeof(eth_configuration), usb_temp_sysctl,
329 	    "A", "Configuration string");
330 #endif
331 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
332 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
333 	    &eth_manufacturer, sizeof(eth_manufacturer), usb_temp_sysctl,
334 	    "A", "Manufacturer string");
335 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
336 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
337 	    &eth_product, sizeof(eth_product), usb_temp_sysctl,
338 	    "A", "Product string");
339 	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
340 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
341 	    &eth_serial_number, sizeof(eth_serial_number), usb_temp_sysctl,
342 	    "A", "Serial number string");
343 }
344 
345 static void
346 eth_uninit(void *arg __unused)
347 {
348 
349 	sysctl_ctx_free(&eth_ctx_list);
350 }
351 
352 SYSINIT(eth_init, SI_SUB_LOCK, SI_ORDER_FIRST, eth_init, NULL);
353 SYSUNINIT(eth_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, eth_uninit, NULL);
354