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 ð_union_desc, 16996263Sobrien ð_header_desc, 17096263Sobrien ð_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 ð_control_interface, 24990075Sobrien ð_data_null_interface, 25090075Sobrien ð_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 ð_config_desc, 26390075Sobrien NULL, 26490075Sobrien}; 26596263Sobrien 26696263Sobrienconst struct usb_temp_device_desc usb_template_cdce = { 26796263Sobrien .getStringDesc = ð_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