usb_template_cdce.c revision 246122
190075Sobrien/* $FreeBSD: head/sys/dev/usb/template/usb_template_cdce.c 246122 2013-01-30 15:26:04Z hselasky $ */
2117395Skan/*-
396263Sobrien * Copyright (c) 2007 Hans Petter Selasky <hselasky@FreeBSD.org>
490075Sobrien * All rights reserved.
590075Sobrien *
690075Sobrien * Redistribution and use in source and binary forms, with or without
790075Sobrien * modification, are permitted provided that the following conditions
890075Sobrien * are met:
990075Sobrien * 1. Redistributions of source code must retain the above copyright
1090075Sobrien *    notice, this list of conditions and the following disclaimer.
1190075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer in the
1390075Sobrien *    documentation and/or other materials provided with the distribution.
1490075Sobrien *
1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1690075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1790075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1890075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1990075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2090075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2190075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2290075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2390075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2490075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2590075Sobrien * SUCH DAMAGE.
2690075Sobrien */
2790075Sobrien
2890075Sobrien/*
2990075Sobrien * This file contains the USB templates for a CDC USB ethernet device.
3090075Sobrien */
3190075Sobrien
3290075Sobrien#ifdef USB_GLOBAL_INCLUDE_FILE
3390075Sobrien#include USB_GLOBAL_INCLUDE_FILE
34117395Skan#else
35117395Skan#include <sys/stdint.h>
36117395Skan#include <sys/stddef.h>
37117395Skan#include <sys/param.h>
3890075Sobrien#include <sys/queue.h>
3990075Sobrien#include <sys/types.h>
4090075Sobrien#include <sys/systm.h>
4190075Sobrien#include <sys/kernel.h>
42103445Skan#include <sys/bus.h>
43103445Skan#include <sys/module.h>
44103445Skan#include <sys/lock.h>
45103445Skan#include <sys/mutex.h>
46103445Skan#include <sys/condvar.h>
47103445Skan#include <sys/sysctl.h>
4890075Sobrien#include <sys/sx.h>
4990075Sobrien#include <sys/unistd.h>
5090075Sobrien#include <sys/callout.h>
5190075Sobrien#include <sys/malloc.h>
5290075Sobrien#include <sys/priv.h>
5390075Sobrien
5490075Sobrien#include <dev/usb/usb.h>
5590075Sobrien#include <dev/usb/usbdi.h>
5690075Sobrien#include <dev/usb/usb_cdc.h>
5790075Sobrien
5890075Sobrien#include <dev/usb/template/usb_template.h>
5990075Sobrien#endif			/* USB_GLOBAL_INCLUDE_FILE */
6090075Sobrien
6190075Sobrienenum {
6290075Sobrien	STRING_LANG_INDEX,
6390075Sobrien	STRING_MAC_INDEX,
6490075Sobrien	STRING_ETH_CONTROL_INDEX,
6590075Sobrien	STRING_ETH_DATA_INDEX,
6690075Sobrien	STRING_ETH_CONFIG_INDEX,
6790075Sobrien	STRING_ETH_VENDOR_INDEX,
6890075Sobrien	STRING_ETH_PRODUCT_INDEX,
6990075Sobrien	STRING_ETH_SERIAL_INDEX,
7090075Sobrien	STRING_ETH_MAX,
7190075Sobrien};
7290075Sobrien
7390075Sobrien#define	STRING_LANG \
7490075Sobrien  0x09, 0x04,				/* American English */
7590075Sobrien
76103445Skan#define	STRING_MAC \
7790075Sobrien  '2', 0, 'A', 0, '2', 0, '3', 0, \
7890075Sobrien  '4', 0, '5', 0, '6', 0, '7', 0, \
7990075Sobrien  '8', 0, '9', 0, 'A', 0, 'B', 0,
8090075Sobrien
8190075Sobrien#define	STRING_ETH_CONTROL \
8290075Sobrien  'U', 0, 'S', 0, 'B', 0, ' ', 0, \
8390075Sobrien  'E', 0, 't', 0, 'h', 0, 'e', 0, \
8490075Sobrien  'r', 0, 'n', 0, 'e', 0, 't', 0, \
8590075Sobrien  ' ', 0, 'C', 0, 'o', 0, 'm', 0, \
8690075Sobrien  'm', 0, ' ', 0, 'i', 0, 'n', 0, \
8790075Sobrien  't', 0, 'e', 0, 'r', 0, 'f', 0, \
8890075Sobrien  'a', 0, 'c', 0, 'e', 0,
8990075Sobrien
9090075Sobrien#define	STRING_ETH_DATA \
9190075Sobrien  'U', 0, 'S', 0, 'B', 0, ' ', 0, \
9290075Sobrien  'E', 0, 't', 0, 'h', 0, 'e', 0, \
9390075Sobrien  'r', 0, 'n', 0, 'e', 0, 't', 0, \
9490075Sobrien  ' ', 0, 'D', 0, 'a', 0, 't', 0, \
9590075Sobrien  'a', 0, ' ', 0, 'i', 0, 'n', 0, \
9690075Sobrien  't', 0, 'e', 0, 'r', 0, 'f', 0, \
9790075Sobrien  'a', 0, 'c', 0, 'e', 0,
9890075Sobrien
9990075Sobrien#define	STRING_ETH_CONFIG \
10090075Sobrien  'D', 0, 'e', 0, 'f', 0, 'a', 0, \
10190075Sobrien  'u', 0, 'l', 0, 't', 0, ' ', 0, \
10290075Sobrien  'c', 0, 'o', 0, 'n', 0, 'f', 0, \
10390075Sobrien  'i', 0, 'g', 0,
10490075Sobrien
10590075Sobrien#define	STRING_ETH_VENDOR \
10690075Sobrien  'F', 0, 'r', 0, 'e', 0, 'e', 0, \
10790075Sobrien  'B', 0, 'S', 0, 'D', 0, ' ', 0, \
10890075Sobrien  'f', 0, 'o', 0, 'u', 0, 'n', 0, \
109117395Skan  'd', 0, 'a', 0, 't', 0, 'i', 0, \
11090075Sobrien  'o', 0, 'n', 0,
11190075Sobrien
11290075Sobrien#define	STRING_ETH_PRODUCT \
113117395Skan  'U', 0, 'S', 0, 'B', 0, ' ', 0, \
114117395Skan  'E', 0, 't', 0, 'h', 0, 'e', 0, \
115117395Skan  'r', 0, 'n', 0, 'e', 0, 't', 0, \
116117395Skan  ' ', 0, 'A', 0, 'd', 0, 'a', 0, \
117117395Skan  'p', 0, 't', 0, 'e', 0, 'r', 0,
118117395Skan
119117395Skan#define	STRING_ETH_SERIAL \
120117395Skan  'D', 0, 'e', 0, 'c', 0, 'e', 0, \
121117395Skan  'm', 0, 'b', 0, 'e', 0, 'r', 0, \
122117395Skan  ' ', 0, '2', 0, '0', 0, '0', 0, \
123117395Skan  '7', 0,
124117395Skan
125117395Skan/* make the real string descriptors */
126117395Skan
12790075SobrienUSB_MAKE_STRING_DESC(STRING_LANG, string_lang);
12890075SobrienUSB_MAKE_STRING_DESC(STRING_MAC, string_mac);
12990075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_CONTROL, string_eth_control);
13090075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_DATA, string_eth_data);
13190075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_CONFIG, string_eth_config);
13290075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_VENDOR, string_eth_vendor);
13390075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_PRODUCT, string_eth_product);
13490075SobrienUSB_MAKE_STRING_DESC(STRING_ETH_SERIAL, string_eth_serial);
13590075Sobrien
13690075Sobrien/* prototypes */
13790075Sobrien
13890075Sobrienstatic usb_temp_get_string_desc_t eth_get_string_desc;
13990075Sobrien
14090075Sobrienstatic const struct usb_cdc_union_descriptor eth_union_desc = {
14190075Sobrien	.bLength = sizeof(eth_union_desc),
14290075Sobrien	.bDescriptorType = UDESC_CS_INTERFACE,
14390075Sobrien	.bDescriptorSubtype = UDESCSUB_CDC_UNION,
14490075Sobrien	.bMasterInterface = 0,		/* this is automatically updated */
14590075Sobrien	.bSlaveInterface[0] = 1,	/* this is automatically updated */
14690075Sobrien};
14790075Sobrien
14890075Sobrienstatic const struct usb_cdc_header_descriptor eth_header_desc = {
14990075Sobrien	.bLength = sizeof(eth_header_desc),
15090075Sobrien	.bDescriptorType = UDESC_CS_INTERFACE,
15190075Sobrien	.bDescriptorSubtype = UDESCSUB_CDC_HEADER,
15290075Sobrien	.bcdCDC[0] = 0x10,
15390075Sobrien	.bcdCDC[1] = 0x01,
15490075Sobrien};
15590075Sobrien
15690075Sobrienstatic const struct usb_cdc_ethernet_descriptor eth_enf_desc = {
15790075Sobrien	.bLength = sizeof(eth_enf_desc),
158117395Skan	.bDescriptorType = UDESC_CS_INTERFACE,
159117395Skan	.bDescriptorSubtype = UDESCSUB_CDC_ENF,
160117395Skan	.iMacAddress = STRING_MAC_INDEX,
161117395Skan	.bmEthernetStatistics = {0, 0, 0, 0},
16296263Sobrien	.wMaxSegmentSize = {0xEA, 0x05},/* 1514 bytes */
16390075Sobrien	.wNumberMCFilters = {0, 0},
16496263Sobrien	.bNumberPowerFilters = 0,
16596263Sobrien};
166117395Skan
167117395Skanstatic const void *eth_control_if_desc[] = {
168117395Skan	&eth_union_desc,
16996263Sobrien	&eth_header_desc,
17096263Sobrien	&eth_enf_desc,
17196263Sobrien	NULL,
172117395Skan};
17396263Sobrien
17490075Sobrienstatic const struct usb_temp_packet_size bulk_mps = {
17590075Sobrien	.mps[USB_SPEED_FULL] = 64,
17690075Sobrien	.mps[USB_SPEED_HIGH] = 512,
17790075Sobrien};
17890075Sobrien
17990075Sobrienstatic const struct usb_temp_packet_size intr_mps = {
18090075Sobrien	.mps[USB_SPEED_FULL] = 8,
18190075Sobrien	.mps[USB_SPEED_HIGH] = 8,
18290075Sobrien};
18390075Sobrien
18490075Sobrienstatic const struct usb_temp_endpoint_desc bulk_in_ep = {
18590075Sobrien	.pPacketSize = &bulk_mps,
18690075Sobrien#ifdef USB_HIP_IN_EP_0
18790075Sobrien	.bEndpointAddress = USB_HIP_IN_EP_0,
18890075Sobrien#else
18990075Sobrien	.bEndpointAddress = UE_DIR_IN,
19090075Sobrien#endif
19190075Sobrien	.bmAttributes = UE_BULK,
19290075Sobrien};
19390075Sobrien
19490075Sobrienstatic const struct usb_temp_endpoint_desc bulk_out_ep = {
19590075Sobrien	.pPacketSize = &bulk_mps,
19690075Sobrien#ifdef USB_HIP_OUT_EP_0
19790075Sobrien	.bEndpointAddress = USB_HIP_OUT_EP_0,
19890075Sobrien#else
19990075Sobrien	.bEndpointAddress = UE_DIR_OUT,
20090075Sobrien#endif
20190075Sobrien	.bmAttributes = UE_BULK,
20290075Sobrien};
20390075Sobrien
20490075Sobrienstatic const struct usb_temp_endpoint_desc intr_in_ep = {
20590075Sobrien	.pPacketSize = &intr_mps,
20690075Sobrien	.bEndpointAddress = UE_DIR_IN,
20790075Sobrien	.bmAttributes = UE_INTERRUPT,
20890075Sobrien};
20990075Sobrien
210117395Skanstatic const struct usb_temp_endpoint_desc *eth_intr_endpoints[] = {
211117395Skan	&intr_in_ep,
212117395Skan	NULL,
213117395Skan};
214117395Skan
215117395Skanstatic const struct usb_temp_interface_desc eth_control_interface = {
216117395Skan	.ppEndpoints = eth_intr_endpoints,
217117395Skan	.ppRawDesc = eth_control_if_desc,
218117395Skan	.bInterfaceClass = UICLASS_CDC,
219117395Skan	.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
220117395Skan	.bInterfaceProtocol = 0,
221117395Skan	.iInterface = STRING_ETH_CONTROL_INDEX,
22290075Sobrien};
22390075Sobrien
22490075Sobrienstatic const struct usb_temp_endpoint_desc *eth_data_endpoints[] = {
22590075Sobrien	&bulk_in_ep,
22690075Sobrien	&bulk_out_ep,
22790075Sobrien	NULL,
22890075Sobrien};
22990075Sobrien
23090075Sobrienstatic const struct usb_temp_interface_desc eth_data_null_interface = {
23190075Sobrien	.ppEndpoints = NULL,		/* no endpoints */
23290075Sobrien	.bInterfaceClass = UICLASS_CDC_DATA,
23390075Sobrien	.bInterfaceSubClass = 0,
23490075Sobrien	.bInterfaceProtocol = 0,
23590075Sobrien	.iInterface = STRING_ETH_DATA_INDEX,
236117395Skan};
237117395Skan
23890075Sobrienstatic const struct usb_temp_interface_desc eth_data_interface = {
23990075Sobrien	.ppEndpoints = eth_data_endpoints,
24090075Sobrien	.bInterfaceClass = UICLASS_CDC_DATA,
24190075Sobrien	.bInterfaceSubClass = UISUBCLASS_DATA,
24290075Sobrien	.bInterfaceProtocol = 0,
24390075Sobrien	.iInterface = STRING_ETH_DATA_INDEX,
24490075Sobrien	.isAltInterface = 1,		/* this is an alternate setting */
24590075Sobrien};
24690075Sobrien
24790075Sobrienstatic const struct usb_temp_interface_desc *eth_interfaces[] = {
24890075Sobrien	&eth_control_interface,
24990075Sobrien	&eth_data_null_interface,
25090075Sobrien	&eth_data_interface,
25190075Sobrien	NULL,
25290075Sobrien};
25390075Sobrien
25490075Sobrienstatic const struct usb_temp_config_desc eth_config_desc = {
25590075Sobrien	.ppIfaceDesc = eth_interfaces,
25690075Sobrien	.bmAttributes = UC_BUS_POWERED,
25790075Sobrien	.bMaxPower = 25,		/* 50 mA */
25890075Sobrien	.iConfiguration = STRING_ETH_CONFIG_INDEX,
25990075Sobrien};
26090075Sobrien
26190075Sobrienstatic const struct usb_temp_config_desc *eth_configs[] = {
26290075Sobrien	&eth_config_desc,
26390075Sobrien	NULL,
26490075Sobrien};
26596263Sobrien
26696263Sobrienconst struct usb_temp_device_desc usb_template_cdce = {
26796263Sobrien	.getStringDesc = &eth_get_string_desc,
26896263Sobrien	.ppConfigDesc = eth_configs,
26996263Sobrien	.idVendor = USB_TEMPLATE_VENDOR,
27096263Sobrien	.idProduct = 0x0001,
27190075Sobrien	.bcdDevice = 0x0100,
27296263Sobrien	.bDeviceClass = UDCLASS_COMM,
27390075Sobrien	.bDeviceSubClass = 0,
27490075Sobrien	.bDeviceProtocol = 0,
27590075Sobrien	.iManufacturer = STRING_ETH_VENDOR_INDEX,
27690075Sobrien	.iProduct = STRING_ETH_PRODUCT_INDEX,
27790075Sobrien	.iSerialNumber = STRING_ETH_SERIAL_INDEX,
27890075Sobrien};
27990075Sobrien
28090075Sobrien/*------------------------------------------------------------------------*
28190075Sobrien *	eth_get_string_desc
28296263Sobrien *
28396263Sobrien * Return values:
28496263Sobrien * NULL: Failure. No such string.
28596263Sobrien * Else: Success. Pointer to string descriptor is returned.
28696263Sobrien *------------------------------------------------------------------------*/
28796263Sobrienstatic const void *
28896263Sobrieneth_get_string_desc(uint16_t lang_id, uint8_t string_index)
28996263Sobrien{
29096263Sobrien	static const void *ptr[STRING_ETH_MAX] = {
29196263Sobrien		[STRING_LANG_INDEX] = &string_lang,
29296263Sobrien		[STRING_MAC_INDEX] = &string_mac,
29396263Sobrien		[STRING_ETH_CONTROL_INDEX] = &string_eth_control,
29496263Sobrien		[STRING_ETH_DATA_INDEX] = &string_eth_data,
29596263Sobrien		[STRING_ETH_CONFIG_INDEX] = &string_eth_config,
29696263Sobrien		[STRING_ETH_VENDOR_INDEX] = &string_eth_vendor,
29796263Sobrien		[STRING_ETH_PRODUCT_INDEX] = &string_eth_product,
298117395Skan		[STRING_ETH_SERIAL_INDEX] = &string_eth_serial,
29990075Sobrien	};
30090075Sobrien
30190075Sobrien	if (string_index == 0) {
30290075Sobrien		return (&string_lang);
30390075Sobrien	}
30490075Sobrien	if (lang_id != 0x0409) {
30590075Sobrien		return (NULL);
30690075Sobrien	}
30790075Sobrien	if (string_index < STRING_ETH_MAX) {
30890075Sobrien		return (ptr[string_index]);
30990075Sobrien	}
31090075Sobrien	return (NULL);
31190075Sobrien}
31290075Sobrien