1223467Shselasky#include <sys/cdefs.h> 2223467Shselasky__FBSDID("$FreeBSD$"); 3223467Shselasky 4223467Shselasky/*- 5223467Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 6223467Shselasky * 7223467Shselasky * Redistribution and use in source and binary forms, with or without 8223467Shselasky * modification, are permitted provided that the following conditions 9223467Shselasky * are met: 10223467Shselasky * 1. Redistributions of source code must retain the above copyright 11223467Shselasky * notice, this list of conditions and the following disclaimer. 12223467Shselasky * 2. Redistributions in binary form must reproduce the above copyright 13223467Shselasky * notice, this list of conditions and the following disclaimer in the 14223467Shselasky * documentation and/or other materials provided with the distribution. 15223467Shselasky * 16223467Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17223467Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18223467Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19223467Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20223467Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21223467Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22223467Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23223467Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24223467Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25223467Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26223467Shselasky * SUCH DAMAGE. 27223467Shselasky */ 28223467Shselasky 29223467Shselasky/* 30223467Shselasky * This file contains the USB template for an USB Modem Device. 31223467Shselasky */ 32223467Shselasky 33223467Shselasky#include <sys/stdint.h> 34223467Shselasky#include <sys/stddef.h> 35223467Shselasky#include <sys/param.h> 36223467Shselasky#include <sys/queue.h> 37223467Shselasky#include <sys/types.h> 38223467Shselasky#include <sys/systm.h> 39223467Shselasky#include <sys/kernel.h> 40223467Shselasky#include <sys/bus.h> 41223467Shselasky#include <sys/module.h> 42223467Shselasky#include <sys/lock.h> 43223467Shselasky#include <sys/mutex.h> 44223467Shselasky#include <sys/condvar.h> 45223467Shselasky#include <sys/sysctl.h> 46223467Shselasky#include <sys/sx.h> 47223467Shselasky#include <sys/unistd.h> 48223467Shselasky#include <sys/callout.h> 49223467Shselasky#include <sys/malloc.h> 50223467Shselasky#include <sys/priv.h> 51223467Shselasky 52223467Shselasky#include <dev/usb/usb.h> 53223467Shselasky#include <dev/usb/usbdi.h> 54223467Shselasky#include <dev/usb/usb_cdc.h> 55223467Shselasky 56223467Shselasky#include <dev/usb/template/usb_template.h> 57223467Shselasky 58223467Shselaskyenum { 59223467Shselasky INDEX_LANG, 60223467Shselasky INDEX_MODEM, 61223467Shselasky INDEX_PRODUCT, 62223467Shselasky INDEX_MAX, 63223467Shselasky}; 64223467Shselasky 65223467Shselasky#define STRING_LANG \ 66223467Shselasky 0x09, 0x04, /* American English */ 67223467Shselasky 68223467Shselasky#define STRING_PRODUCT \ 69223467Shselasky 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ 70223467Shselasky 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ 71223467Shselasky 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, 72223467Shselasky 73223467Shselasky#define STRING_MODEM \ 74223467Shselasky 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ 75223467Shselasky 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, 76223467Shselasky 77223467Shselasky/* make the real string descriptors */ 78223467Shselasky 79223467ShselaskyUSB_MAKE_STRING_DESC(STRING_LANG, string_lang); 80223467ShselaskyUSB_MAKE_STRING_DESC(STRING_MODEM, string_modem); 81223467ShselaskyUSB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); 82223467Shselasky 83223467Shselasky#define MODEM_IFACE_0 0 84223467Shselasky#define MODEM_IFACE_1 1 85223467Shselasky 86223467Shselasky/* prototypes */ 87223467Shselasky 88223467Shselaskystatic const struct usb_temp_packet_size modem_bulk_mps = { 89223467Shselasky .mps[USB_SPEED_LOW] = 8, 90223467Shselasky .mps[USB_SPEED_FULL] = 64, 91223467Shselasky .mps[USB_SPEED_HIGH] = 512, 92223467Shselasky}; 93223467Shselasky 94223467Shselaskystatic const struct usb_temp_packet_size modem_intr_mps = { 95223467Shselasky .mps[USB_SPEED_LOW] = 8, 96223467Shselasky .mps[USB_SPEED_FULL] = 8, 97223467Shselasky .mps[USB_SPEED_HIGH] = 8, 98223467Shselasky}; 99223467Shselasky 100223467Shselaskystatic const struct usb_temp_interval modem_intr_interval = { 101229103Shselasky .bInterval[USB_SPEED_LOW] = 8, /* 8ms */ 102229103Shselasky .bInterval[USB_SPEED_FULL] = 8, /* 8ms */ 103229103Shselasky .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */ 104223467Shselasky}; 105223467Shselasky 106223467Shselaskystatic const struct usb_temp_endpoint_desc modem_ep_0 = { 107223467Shselasky .pPacketSize = &modem_intr_mps, 108223467Shselasky .pIntervals = &modem_intr_interval, 109223467Shselasky .bEndpointAddress = UE_DIR_IN, 110223467Shselasky .bmAttributes = UE_INTERRUPT, 111223467Shselasky}; 112223467Shselasky 113223467Shselaskystatic const struct usb_temp_endpoint_desc modem_ep_1 = { 114223467Shselasky .pPacketSize = &modem_bulk_mps, 115223467Shselasky .bEndpointAddress = UE_DIR_OUT, 116223467Shselasky .bmAttributes = UE_BULK, 117223467Shselasky}; 118223467Shselasky 119223467Shselaskystatic const struct usb_temp_endpoint_desc modem_ep_2 = { 120223467Shselasky .pPacketSize = &modem_bulk_mps, 121223467Shselasky .bEndpointAddress = UE_DIR_IN, 122223467Shselasky .bmAttributes = UE_BULK, 123223467Shselasky}; 124223467Shselasky 125223467Shselaskystatic const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 126223467Shselasky &modem_ep_0, 127223467Shselasky NULL, 128223467Shselasky}; 129223467Shselasky 130223467Shselaskystatic const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 131223467Shselasky &modem_ep_1, 132223467Shselasky &modem_ep_2, 133223467Shselasky NULL, 134223467Shselasky}; 135223467Shselasky 136223467Shselaskystatic const uint8_t modem_raw_desc_0[] = { 137223467Shselasky 0x05, 0x24, 0x00, 0x10, 0x01 138223467Shselasky}; 139223467Shselasky 140223467Shselaskystatic const uint8_t modem_raw_desc_1[] = { 141223467Shselasky 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 142223467Shselasky}; 143223467Shselasky 144223467Shselaskystatic const uint8_t modem_raw_desc_2[] = { 145223467Shselasky 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 146223467Shselasky}; 147223467Shselasky 148223467Shselaskystatic const uint8_t modem_raw_desc_3[] = { 149223467Shselasky 0x04, 0x24, 0x02, 0x07 150223467Shselasky}; 151223467Shselasky 152223467Shselaskystatic const void *modem_iface_0_desc[] = { 153223467Shselasky &modem_raw_desc_0, 154223467Shselasky &modem_raw_desc_1, 155223467Shselasky &modem_raw_desc_2, 156223467Shselasky &modem_raw_desc_3, 157223467Shselasky NULL, 158223467Shselasky}; 159223467Shselasky 160223467Shselaskystatic const struct usb_temp_interface_desc modem_iface_0 = { 161223467Shselasky .ppRawDesc = modem_iface_0_desc, 162223467Shselasky .ppEndpoints = modem_iface_0_ep, 163223467Shselasky .bInterfaceClass = 2, 164223467Shselasky .bInterfaceSubClass = 2, 165223467Shselasky .bInterfaceProtocol = 1, 166223467Shselasky .iInterface = INDEX_MODEM, 167223467Shselasky}; 168223467Shselasky 169223467Shselaskystatic const struct usb_temp_interface_desc modem_iface_1 = { 170223467Shselasky .ppEndpoints = modem_iface_1_ep, 171223467Shselasky .bInterfaceClass = 10, 172223467Shselasky .bInterfaceSubClass = 0, 173223467Shselasky .bInterfaceProtocol = 0, 174223467Shselasky .iInterface = INDEX_MODEM, 175223467Shselasky}; 176223467Shselasky 177223467Shselaskystatic const struct usb_temp_interface_desc *modem_interfaces[] = { 178223467Shselasky &modem_iface_0, 179223467Shselasky &modem_iface_1, 180223467Shselasky NULL, 181223467Shselasky}; 182223467Shselasky 183223467Shselaskystatic const struct usb_temp_config_desc modem_config_desc = { 184223467Shselasky .ppIfaceDesc = modem_interfaces, 185223467Shselasky .bmAttributes = UC_BUS_POWERED, 186223467Shselasky .bMaxPower = 25, /* 50 mA */ 187223467Shselasky .iConfiguration = INDEX_PRODUCT, 188223467Shselasky}; 189223467Shselasky 190223467Shselaskystatic const struct usb_temp_config_desc *modem_configs[] = { 191223467Shselasky &modem_config_desc, 192223467Shselasky NULL, 193223467Shselasky}; 194223467Shselasky 195223467Shselaskystatic usb_temp_get_string_desc_t modem_get_string_desc; 196223467Shselaskystatic usb_temp_get_vendor_desc_t modem_get_vendor_desc; 197223467Shselasky 198223467Shselaskyconst struct usb_temp_device_desc usb_template_modem = { 199223467Shselasky .getStringDesc = &modem_get_string_desc, 200223467Shselasky .getVendorDesc = &modem_get_vendor_desc, 201223467Shselasky .ppConfigDesc = modem_configs, 202223467Shselasky .idVendor = USB_TEMPLATE_VENDOR, 203223467Shselasky .idProduct = 0x000E, 204223467Shselasky .bcdDevice = 0x0100, 205223467Shselasky .bDeviceClass = UDCLASS_COMM, 206223467Shselasky .bDeviceSubClass = 0, 207223467Shselasky .bDeviceProtocol = 0, 208223467Shselasky .iManufacturer = 0, 209223467Shselasky .iProduct = INDEX_PRODUCT, 210223467Shselasky .iSerialNumber = 0, 211223467Shselasky}; 212223467Shselasky 213223467Shselasky/*------------------------------------------------------------------------* 214223467Shselasky * modem_get_vendor_desc 215223467Shselasky * 216223467Shselasky * Return values: 217223467Shselasky * NULL: Failure. No such vendor descriptor. 218223467Shselasky * Else: Success. Pointer to vendor descriptor is returned. 219223467Shselasky *------------------------------------------------------------------------*/ 220223467Shselaskystatic const void * 221223467Shselaskymodem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 222223467Shselasky{ 223223467Shselasky return (NULL); 224223467Shselasky} 225223467Shselasky 226223467Shselasky/*------------------------------------------------------------------------* 227223467Shselasky * modem_get_string_desc 228223467Shselasky * 229223467Shselasky * Return values: 230223467Shselasky * NULL: Failure. No such string. 231223467Shselasky * Else: Success. Pointer to string descriptor is returned. 232223467Shselasky *------------------------------------------------------------------------*/ 233223467Shselaskystatic const void * 234223467Shselaskymodem_get_string_desc(uint16_t lang_id, uint8_t string_index) 235223467Shselasky{ 236223467Shselasky static const void *ptr[INDEX_MAX] = { 237223467Shselasky [INDEX_LANG] = &string_lang, 238223467Shselasky [INDEX_MODEM] = &string_modem, 239223467Shselasky [INDEX_PRODUCT] = &string_product, 240223467Shselasky }; 241223467Shselasky 242223467Shselasky if (string_index == 0) { 243223467Shselasky return (&string_lang); 244223467Shselasky } 245223467Shselasky if (lang_id != 0x0409) { 246223467Shselasky return (NULL); 247223467Shselasky } 248223467Shselasky if (string_index < INDEX_MAX) { 249223467Shselasky return (ptr[string_index]); 250223467Shselasky } 251223467Shselasky return (NULL); 252223467Shselasky} 253