usb_template_modem.c revision 223467
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/template/usb_template_modem.c 223467 2011-06-23 07:54:03Z hselasky $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 6187494Semax * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred 29184610Salfred/* 30184610Salfred * This file contains the USB template for an USB Modem Device. 31184610Salfred */ 32184610Salfred 33184610Salfred#include <sys/stdint.h> 34187494Semax#include <sys/stddef.h> 35187494Semax#include <sys/param.h> 36187741Semax#include <sys/queue.h> 37187494Semax#include <sys/types.h> 38187494Semax#include <sys/systm.h> 39187494Semax#include <sys/kernel.h> 40187741Semax#include <sys/bus.h> 41187494Semax#include <sys/module.h> 42187741Semax#include <sys/lock.h> 43187741Semax#include <sys/mutex.h> 44187741Semax#include <sys/condvar.h> 45187494Semax#include <sys/sysctl.h> 46187741Semax#include <sys/sx.h> 47187741Semax#include <sys/unistd.h> 48187741Semax#include <sys/callout.h> 49187741Semax#include <sys/malloc.h> 50187494Semax#include <sys/priv.h> 51187494Semax 52187494Semax#include <dev/usb/usb.h> 53187494Semax#include <dev/usb/usbdi.h> 54187741Semax#include <dev/usb/usb_cdc.h> 55187494Semax 56187494Semax#include <dev/usb/template/usb_template.h> 57187494Semax 58187494Semaxenum { 59187494Semax INDEX_LANG, 60187494Semax INDEX_MODEM, 61187494Semax INDEX_PRODUCT, 62187741Semax INDEX_MAX, 63187741Semax}; 64187741Semax 65187741Semax#define STRING_LANG \ 66187741Semax 0x09, 0x04, /* American English */ 67187741Semax 68187494Semax#define STRING_PRODUCT \ 69187741Semax 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ 70187741Semax 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ 71187741Semax 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, 72187741Semax 73187741Semax#define STRING_MODEM \ 74187494Semax 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ 75187494Semax 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, 76187494Semax 77187494Semax/* make the real string descriptors */ 78187494Semax 79187494SemaxUSB_MAKE_STRING_DESC(STRING_LANG, string_lang); 80187741SemaxUSB_MAKE_STRING_DESC(STRING_MODEM, string_modem); 81187741SemaxUSB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); 82187741Semax 83187741Semax#define MODEM_IFACE_0 0 84187494Semax#define MODEM_IFACE_1 1 85187494Semax 86187741Semax/* prototypes */ 87187741Semax 88187741Semaxstatic const struct usb_temp_packet_size modem_bulk_mps = { 89187741Semax .mps[USB_SPEED_LOW] = 8, 90189002Sed .mps[USB_SPEED_FULL] = 64, 91187741Semax .mps[USB_SPEED_HIGH] = 512, 92187741Semax}; 93187494Semax 94187494Semaxstatic const struct usb_temp_packet_size modem_intr_mps = { 95188746Sthompsa .mps[USB_SPEED_LOW] = 8, 96188942Sthompsa .mps[USB_SPEED_FULL] = 8, 97188942Sthompsa .mps[USB_SPEED_HIGH] = 8, 98188942Sthompsa}; 99184610Salfred 100194228Sthompsastatic const struct usb_temp_interval modem_intr_interval = { 101184610Salfred .bInterval[USB_SPEED_LOW] = 10, 102188942Sthompsa .bInterval[USB_SPEED_FULL] = 10, 103188942Sthompsa .bInterval[USB_SPEED_HIGH] = 10 * 8, 104188942Sthompsa}; 105188942Sthompsa 106188942Sthompsastatic const struct usb_temp_endpoint_desc modem_ep_0 = { 107188942Sthompsa .pPacketSize = &modem_intr_mps, 108188942Sthompsa .pIntervals = &modem_intr_interval, 109188942Sthompsa .bEndpointAddress = UE_DIR_IN, 110184610Salfred .bmAttributes = UE_INTERRUPT, 111184610Salfred}; 112187494Semax 113184610Salfredstatic const struct usb_temp_endpoint_desc modem_ep_1 = { 114184610Salfred .pPacketSize = &modem_bulk_mps, 115184610Salfred .bEndpointAddress = UE_DIR_OUT, 116184610Salfred .bmAttributes = UE_BULK, 117184610Salfred}; 118184610Salfred 119184610Salfredstatic const struct usb_temp_endpoint_desc modem_ep_2 = { 120192909Sthompsa .pPacketSize = &modem_bulk_mps, 121184610Salfred .bEndpointAddress = UE_DIR_IN, 122187494Semax .bmAttributes = UE_BULK, 123187494Semax}; 124187494Semax 125187494Semaxstatic const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 126184610Salfred &modem_ep_0, 127187741Semax NULL, 128187494Semax}; 129184610Salfred 130194228Sthompsastatic const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 131187741Semax &modem_ep_1, 132187494Semax &modem_ep_2, 133187494Semax NULL, 134187494Semax}; 135187494Semax 136187494Semaxstatic const uint8_t modem_raw_desc_0[] = { 137187494Semax 0x05, 0x24, 0x00, 0x10, 0x01 138187494Semax}; 139187494Semax 140184610Salfredstatic const uint8_t modem_raw_desc_1[] = { 141184610Salfred 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 142187494Semax}; 143184610Salfred 144187494Semaxstatic const uint8_t modem_raw_desc_2[] = { 145187494Semax 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 146187494Semax}; 147184610Salfred 148187494Semaxstatic const uint8_t modem_raw_desc_3[] = { 149187494Semax 0x04, 0x24, 0x02, 0x07 150184610Salfred}; 151184610Salfred 152184610Salfredstatic const void *modem_iface_0_desc[] = { 153184610Salfred &modem_raw_desc_0, 154184610Salfred &modem_raw_desc_1, 155187494Semax &modem_raw_desc_2, 156184610Salfred &modem_raw_desc_3, 157187494Semax NULL, 158187494Semax}; 159187494Semax 160187494Semaxstatic const struct usb_temp_interface_desc modem_iface_0 = { 161187494Semax .ppRawDesc = modem_iface_0_desc, 162187494Semax .ppEndpoints = modem_iface_0_ep, 163187494Semax .bInterfaceClass = 2, 164184610Salfred .bInterfaceSubClass = 2, 165187494Semax .bInterfaceProtocol = 1, 166187494Semax .iInterface = INDEX_MODEM, 167184610Salfred}; 168184610Salfred 169184610Salfredstatic const struct usb_temp_interface_desc modem_iface_1 = { 170184610Salfred .ppEndpoints = modem_iface_1_ep, 171184610Salfred .bInterfaceClass = 10, 172187494Semax .bInterfaceSubClass = 0, 173187494Semax .bInterfaceProtocol = 0, 174184610Salfred .iInterface = INDEX_MODEM, 175184610Salfred}; 176184610Salfred 177184610Salfredstatic const struct usb_temp_interface_desc *modem_interfaces[] = { 178184610Salfred &modem_iface_0, 179184610Salfred &modem_iface_1, 180184610Salfred NULL, 181184610Salfred}; 182184610Salfred 183184610Salfredstatic const struct usb_temp_config_desc modem_config_desc = { 184184610Salfred .ppIfaceDesc = modem_interfaces, 185184610Salfred .bmAttributes = UC_BUS_POWERED, 186184610Salfred .bMaxPower = 25, /* 50 mA */ 187184610Salfred .iConfiguration = INDEX_PRODUCT, 188184610Salfred}; 189184610Salfred 190184610Salfredstatic const struct usb_temp_config_desc *modem_configs[] = { 191184610Salfred &modem_config_desc, 192184610Salfred NULL, 193184610Salfred}; 194184610Salfred 195184610Salfredstatic usb_temp_get_string_desc_t modem_get_string_desc; 196184610Salfredstatic usb_temp_get_vendor_desc_t modem_get_vendor_desc; 197184610Salfred 198184610Salfredconst struct usb_temp_device_desc usb_template_modem = { 199184610Salfred .getStringDesc = &modem_get_string_desc, 200184610Salfred .getVendorDesc = &modem_get_vendor_desc, 201184610Salfred .ppConfigDesc = modem_configs, 202184610Salfred .idVendor = USB_TEMPLATE_VENDOR, 203184610Salfred .idProduct = 0x000E, 204184610Salfred .bcdDevice = 0x0100, 205184610Salfred .bDeviceClass = UDCLASS_COMM, 206184610Salfred .bDeviceSubClass = 0, 207184610Salfred .bDeviceProtocol = 0, 208184610Salfred .iManufacturer = 0, 209184610Salfred .iProduct = INDEX_PRODUCT, 210184610Salfred .iSerialNumber = 0, 211184610Salfred}; 212184610Salfred 213184610Salfred/*------------------------------------------------------------------------* 214184610Salfred * modem_get_vendor_desc 215184610Salfred * 216187494Semax * Return values: 217184610Salfred * NULL: Failure. No such vendor descriptor. 218184610Salfred * Else: Success. Pointer to vendor descriptor is returned. 219184610Salfred *------------------------------------------------------------------------*/ 220187494Semaxstatic const void * 221187494Semaxmodem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 222187494Semax{ 223187494Semax return (NULL); 224187494Semax} 225187494Semax 226187494Semax/*------------------------------------------------------------------------* 227187494Semax * modem_get_string_desc 228187494Semax * 229187494Semax * Return values: 230187494Semax * NULL: Failure. No such string. 231187494Semax * Else: Success. Pointer to string descriptor is returned. 232184610Salfred *------------------------------------------------------------------------*/ 233184610Salfredstatic const void * 234187494Semaxmodem_get_string_desc(uint16_t lang_id, uint8_t string_index) 235187494Semax{ 236187494Semax static const void *ptr[INDEX_MAX] = { 237187494Semax [INDEX_LANG] = &string_lang, 238187494Semax [INDEX_MODEM] = &string_modem, 239187494Semax [INDEX_PRODUCT] = &string_product, 240184610Salfred }; 241193045Sthompsa 242193045Sthompsa if (string_index == 0) { 243193045Sthompsa return (&string_lang); 244193045Sthompsa } 245193045Sthompsa if (lang_id != 0x0409) { 246193045Sthompsa return (NULL); 247184610Salfred } 248187741Semax if (string_index < INDEX_MAX) { 249192984Sthompsa return (ptr[string_index]); 250184610Salfred } 251187494Semax return (NULL); 252187494Semax} 253187494Semax