usb_template_cdce.c 11.1 KB
Newer Older
1
/* $FreeBSD$ */
2
/*-
3
4
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
 *
5
 * Copyright (c) 2007 Hans Petter Selasky <hselasky@FreeBSD.org>
6
 * Copyright (c) 2018 The FreeBSD Foundation
7
8
 * All rights reserved.
 *
9
10
11
 * Portions of this software were developed by Edward Tomasz Napierala
 * under sponsorship from the FreeBSD Foundation.
 *
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * This file contains the USB templates for a CDC USB ethernet device.
 */

38
39
40
#ifdef USB_GLOBAL_INCLUDE_FILE
#include USB_GLOBAL_INCLUDE_FILE
#else
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <sys/stdint.h>
#include <sys/stddef.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>

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
65
#include <dev/usb/usb_ioctl.h>
#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
72
73
74
75
76
77
78
79
	ETH_LANG_INDEX,
	ETH_MAC_INDEX,
	ETH_CONTROL_INDEX,
	ETH_DATA_INDEX,
	ETH_CONFIGURATION_INDEX,
	ETH_MANUFACTURER_INDEX,
	ETH_PRODUCT_INDEX,
	ETH_SERIAL_NUMBER_INDEX,
	ETH_MAX_INDEX,
80
81
};

82
#define	ETH_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
83
#define	ETH_DEFAULT_PRODUCT_ID		0x27e1
84
85
86
87
#define	ETH_DEFAULT_MAC			"2A02030405060789AB"
#define	ETH_DEFAULT_CONTROL		"USB Ethernet Comm Interface"
#define	ETH_DEFAULT_DATA		"USB Ethernet Data Interface"
#define	ETH_DEFAULT_CONFIG		"Default Config"
88
#define	ETH_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
89
90
#define	ETH_DEFAULT_PRODUCT		"USB Ethernet Adapter"
#define	ETH_DEFAULT_SERIAL_NUMBER	"December 2007"
91

92
93
94
95
96
97
98
static struct usb_string_descriptor	eth_mac;
static struct usb_string_descriptor	eth_control;
static struct usb_string_descriptor	eth_data;
static struct usb_string_descriptor	eth_configuration;
static struct usb_string_descriptor	eth_manufacturer;
static struct usb_string_descriptor	eth_product;
static struct usb_string_descriptor	eth_serial_number;
99

100
static struct sysctl_ctx_list		eth_ctx_list;
101
102
103

/* prototypes */

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
108
109
110
111
112
113
	.bLength = sizeof(eth_union_desc),
	.bDescriptorType = UDESC_CS_INTERFACE,
	.bDescriptorSubtype = UDESCSUB_CDC_UNION,
	.bMasterInterface = 0,		/* this is automatically updated */
	.bSlaveInterface[0] = 1,	/* this is automatically updated */
};

114
static const struct usb_cdc_header_descriptor eth_header_desc = {
115
116
117
118
119
120
121
	.bLength = sizeof(eth_header_desc),
	.bDescriptorType = UDESC_CS_INTERFACE,
	.bDescriptorSubtype = UDESCSUB_CDC_HEADER,
	.bcdCDC[0] = 0x10,
	.bcdCDC[1] = 0x01,
};

122
static const struct usb_cdc_ethernet_descriptor eth_enf_desc = {
123
124
125
	.bLength = sizeof(eth_enf_desc),
	.bDescriptorType = UDESC_CS_INTERFACE,
	.bDescriptorSubtype = UDESCSUB_CDC_ENF,
126
	.iMacAddress = ETH_MAC_INDEX,
127
128
129
130
131
132
133
134
135
136
137
138
139
	.bmEthernetStatistics = {0, 0, 0, 0},
	.wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */
	.wNumberMCFilters = {0, 0},
	.bNumberPowerFilters = 0,
};

static const void *eth_control_if_desc[] = {
	&eth_union_desc,
	&eth_header_desc,
	&eth_enf_desc,
	NULL,
};

140
static const struct usb_temp_packet_size bulk_mps = {
141
142
143
144
	.mps[USB_SPEED_FULL] = 64,
	.mps[USB_SPEED_HIGH] = 512,
};

145
static const struct usb_temp_packet_size intr_mps = {
146
147
148
149
	.mps[USB_SPEED_FULL] = 8,
	.mps[USB_SPEED_HIGH] = 8,
};

150
static const struct usb_temp_endpoint_desc bulk_in_ep = {
151
152
153
154
155
156
157
158
159
	.pPacketSize = &bulk_mps,
#ifdef USB_HIP_IN_EP_0
	.bEndpointAddress = USB_HIP_IN_EP_0,
#else
	.bEndpointAddress = UE_DIR_IN,
#endif
	.bmAttributes = UE_BULK,
};

160
static const struct usb_temp_endpoint_desc bulk_out_ep = {
161
162
163
164
165
166
167
168
169
	.pPacketSize = &bulk_mps,
#ifdef USB_HIP_OUT_EP_0
	.bEndpointAddress = USB_HIP_OUT_EP_0,
#else
	.bEndpointAddress = UE_DIR_OUT,
#endif
	.bmAttributes = UE_BULK,
};

170
static const struct usb_temp_endpoint_desc intr_in_ep = {
171
172
173
174
175
	.pPacketSize = &intr_mps,
	.bEndpointAddress = UE_DIR_IN,
	.bmAttributes = UE_INTERRUPT,
};

176
static const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = {
177
178
179
180
	&intr_in_ep,
	NULL,
};

181
static const struct usb_temp_interface_desc eth_control_interface = {
182
183
184
185
186
	.ppEndpoints = eth_intr_endpoints,
	.ppRawDesc = eth_control_if_desc,
	.bInterfaceClass = UICLASS_CDC,
	.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
	.bInterfaceProtocol = 0,
187
	.iInterface = ETH_CONTROL_INDEX,
188
189
};

190
static const struct usb_temp_endpoint_desc *eth_data_endpoints[] = {
191
192
193
194
195
	&bulk_in_ep,
	&bulk_out_ep,
	NULL,
};

196
static const struct usb_temp_interface_desc eth_data_null_interface = {
197
198
199
200
	.ppEndpoints = NULL,		/* no endpoints */
	.bInterfaceClass = UICLASS_CDC_DATA,
	.bInterfaceSubClass = 0,
	.bInterfaceProtocol = 0,
201
	.iInterface = ETH_DATA_INDEX,
202
203
};

204
static const struct usb_temp_interface_desc eth_data_interface = {
205
206
207
208
	.ppEndpoints = eth_data_endpoints,
	.bInterfaceClass = UICLASS_CDC_DATA,
	.bInterfaceSubClass = UISUBCLASS_DATA,
	.bInterfaceProtocol = 0,
209
	.iInterface = ETH_DATA_INDEX,
210
211
212
	.isAltInterface = 1,		/* this is an alternate setting */
};

213
static const struct usb_temp_interface_desc *eth_interfaces[] = {
214
215
216
217
218
219
	&eth_control_interface,
	&eth_data_null_interface,
	&eth_data_interface,
	NULL,
};

220
static const struct usb_temp_config_desc eth_config_desc = {
221
222
223
	.ppIfaceDesc = eth_interfaces,
	.bmAttributes = UC_BUS_POWERED,
	.bMaxPower = 25,		/* 50 mA */
224
	.iConfiguration = ETH_CONFIGURATION_INDEX,
225
226
};

227
static const struct usb_temp_config_desc *eth_configs[] = {
228
229
230
231
	&eth_config_desc,
	NULL,
};

232
struct usb_temp_device_desc usb_template_cdce = {
233
234
	.getStringDesc = &eth_get_string_desc,
	.ppConfigDesc = eth_configs,
235
236
	.idVendor = ETH_DEFAULT_VENDOR_ID,
	.idProduct = ETH_DEFAULT_PRODUCT_ID,
237
238
239
240
	.bcdDevice = 0x0100,
	.bDeviceClass = UDCLASS_COMM,
	.bDeviceSubClass = 0,
	.bDeviceProtocol = 0,
241
242
243
	.iManufacturer = ETH_MANUFACTURER_INDEX,
	.iProduct = ETH_PRODUCT_INDEX,
	.iSerialNumber = ETH_SERIAL_NUMBER_INDEX,
244
245
246
247
248
249
250
251
252
253
254
255
};

/*------------------------------------------------------------------------*
 *	eth_get_string_desc
 *
 * Return values:
 * NULL: Failure. No such string.
 * Else: Success. Pointer to string descriptor is returned.
 *------------------------------------------------------------------------*/
static const void *
eth_get_string_desc(uint16_t lang_id, uint8_t string_index)
{
256
257
258
259
260
261
262
263
264
	static const void *ptr[ETH_MAX_INDEX] = {
		[ETH_LANG_INDEX] = &usb_string_lang_en,
		[ETH_MAC_INDEX] = &eth_mac,
		[ETH_CONTROL_INDEX] = &eth_control,
		[ETH_DATA_INDEX] = &eth_data,
		[ETH_CONFIGURATION_INDEX] = &eth_configuration,
		[ETH_MANUFACTURER_INDEX] = &eth_manufacturer,
		[ETH_PRODUCT_INDEX] = &eth_product,
		[ETH_SERIAL_NUMBER_INDEX] = &eth_serial_number,
265
266
267
	};

	if (string_index == 0) {
268
		return (&usb_string_lang_en);
269
270
271
272
	}
	if (lang_id != 0x0409) {
		return (NULL);
	}
273
	if (string_index < ETH_MAX_INDEX) {
274
275
276
277
		return (ptr[string_index]);
	}
	return (NULL);
}
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

static void
eth_init(void *arg __unused)
{
	struct sysctl_oid *parent;
	char parent_name[3];

	usb_make_str_desc(&eth_mac, sizeof(eth_mac),
	    ETH_DEFAULT_MAC);
	usb_make_str_desc(&eth_control, sizeof(eth_control),
	    ETH_DEFAULT_CONTROL);
	usb_make_str_desc(&eth_data, sizeof(eth_data),
	    ETH_DEFAULT_DATA);
	usb_make_str_desc(&eth_configuration, sizeof(eth_configuration),
	    ETH_DEFAULT_CONFIG);
	usb_make_str_desc(&eth_manufacturer, sizeof(eth_manufacturer),
	    ETH_DEFAULT_MANUFACTURER);
	usb_make_str_desc(&eth_product, sizeof(eth_product),
	    ETH_DEFAULT_PRODUCT);
	usb_make_str_desc(&eth_serial_number, sizeof(eth_serial_number),
	    ETH_DEFAULT_SERIAL_NUMBER);

	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_CDCE);
	sysctl_ctx_init(&eth_ctx_list);

	parent = SYSCTL_ADD_NODE(&eth_ctx_list,
	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
	    parent_name, CTLFLAG_RW,
	    0, "USB CDC Ethernet device side template");
	SYSCTL_ADD_U16(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "vendor_id", CTLFLAG_RWTUN,
	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
	SYSCTL_ADD_U16(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "product_id", CTLFLAG_RWTUN,
	    &usb_template_cdce.idProduct, 1, "Product identifier");
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "mac", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_mac, sizeof(eth_mac), usb_temp_sysctl,
	    "A", "MAC address string");
#if 0
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "control", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_control, sizeof(eth_control), usb_temp_sysctl,
	    "A", "Control interface string");
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "data", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_data, sizeof(eth_data), usb_temp_sysctl,
	    "A", "Data interface string");
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "configuration", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_configuration, sizeof(eth_configuration), usb_temp_sysctl,
	    "A", "Configuration string");
#endif
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_manufacturer, sizeof(eth_manufacturer), usb_temp_sysctl,
	    "A", "Manufacturer string");
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_product, sizeof(eth_product), usb_temp_sysctl,
	    "A", "Product string");
	SYSCTL_ADD_PROC(&eth_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
	    &eth_serial_number, sizeof(eth_serial_number), usb_temp_sysctl,
	    "A", "Serial number string");
}

static void
eth_uninit(void *arg __unused)
{

	sysctl_ctx_free(&eth_ctx_list);
}

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);