1 /* $FreeBSD$ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * This file contains the USB template for an USB Modem Device. 31 */ 32 33 #ifdef USB_GLOBAL_INCLUDE_FILE 34 #include USB_GLOBAL_INCLUDE_FILE 35 #else 36 #include <sys/stdint.h> 37 #include <sys/stddef.h> 38 #include <sys/param.h> 39 #include <sys/queue.h> 40 #include <sys/types.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/bus.h> 44 #include <sys/module.h> 45 #include <sys/lock.h> 46 #include <sys/mutex.h> 47 #include <sys/condvar.h> 48 #include <sys/sysctl.h> 49 #include <sys/sx.h> 50 #include <sys/unistd.h> 51 #include <sys/callout.h> 52 #include <sys/malloc.h> 53 #include <sys/priv.h> 54 55 #include <dev/usb/usb.h> 56 #include <dev/usb/usbdi.h> 57 #include <dev/usb/usb_core.h> 58 #include <dev/usb/usb_cdc.h> 59 60 #include <dev/usb/template/usb_template.h> 61 #endif /* USB_GLOBAL_INCLUDE_FILE */ 62 63 enum { 64 INDEX_LANG, 65 INDEX_MODEM, 66 INDEX_PRODUCT, 67 INDEX_MAX, 68 }; 69 70 #define STRING_PRODUCT \ 71 "M\0o\0d\0e\0m\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" 72 73 #define STRING_MODEM \ 74 "M\0o\0d\0e\0m\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 75 76 /* make the real string descriptors */ 77 78 USB_MAKE_STRING_DESC(STRING_MODEM, string_modem); 79 USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); 80 81 #define MODEM_IFACE_0 0 82 #define MODEM_IFACE_1 1 83 84 /* prototypes */ 85 86 static const struct usb_temp_packet_size modem_bulk_mps = { 87 .mps[USB_SPEED_LOW] = 8, 88 .mps[USB_SPEED_FULL] = 64, 89 .mps[USB_SPEED_HIGH] = 512, 90 }; 91 92 static const struct usb_temp_packet_size modem_intr_mps = { 93 .mps[USB_SPEED_LOW] = 8, 94 .mps[USB_SPEED_FULL] = 8, 95 .mps[USB_SPEED_HIGH] = 8, 96 }; 97 98 static const struct usb_temp_interval modem_intr_interval = { 99 .bInterval[USB_SPEED_LOW] = 8, /* 8ms */ 100 .bInterval[USB_SPEED_FULL] = 8, /* 8ms */ 101 .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */ 102 }; 103 104 static const struct usb_temp_endpoint_desc modem_ep_0 = { 105 .pPacketSize = &modem_intr_mps, 106 .pIntervals = &modem_intr_interval, 107 .bEndpointAddress = UE_DIR_IN, 108 .bmAttributes = UE_INTERRUPT, 109 }; 110 111 static const struct usb_temp_endpoint_desc modem_ep_1 = { 112 .pPacketSize = &modem_bulk_mps, 113 .bEndpointAddress = UE_DIR_OUT, 114 .bmAttributes = UE_BULK, 115 }; 116 117 static const struct usb_temp_endpoint_desc modem_ep_2 = { 118 .pPacketSize = &modem_bulk_mps, 119 .bEndpointAddress = UE_DIR_IN, 120 .bmAttributes = UE_BULK, 121 }; 122 123 static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 124 &modem_ep_0, 125 NULL, 126 }; 127 128 static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 129 &modem_ep_1, 130 &modem_ep_2, 131 NULL, 132 }; 133 134 static const uint8_t modem_raw_desc_0[] = { 135 0x05, 0x24, 0x00, 0x10, 0x01 136 }; 137 138 static const uint8_t modem_raw_desc_1[] = { 139 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 140 }; 141 142 static const uint8_t modem_raw_desc_2[] = { 143 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 144 }; 145 146 static const uint8_t modem_raw_desc_3[] = { 147 0x04, 0x24, 0x02, 0x07 148 }; 149 150 static const void *modem_iface_0_desc[] = { 151 &modem_raw_desc_0, 152 &modem_raw_desc_1, 153 &modem_raw_desc_2, 154 &modem_raw_desc_3, 155 NULL, 156 }; 157 158 static const struct usb_temp_interface_desc modem_iface_0 = { 159 .ppRawDesc = modem_iface_0_desc, 160 .ppEndpoints = modem_iface_0_ep, 161 .bInterfaceClass = UICLASS_CDC, 162 .bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL, 163 .bInterfaceProtocol = UIPROTO_CDC_AT, 164 .iInterface = INDEX_MODEM, 165 }; 166 167 static const struct usb_temp_interface_desc modem_iface_1 = { 168 .ppEndpoints = modem_iface_1_ep, 169 .bInterfaceClass = UICLASS_CDC_DATA, 170 .bInterfaceSubClass = UISUBCLASS_DATA, 171 .bInterfaceProtocol = UIPROTO_CDC_NONE, 172 .iInterface = INDEX_MODEM, 173 }; 174 175 static const struct usb_temp_interface_desc *modem_interfaces[] = { 176 &modem_iface_0, 177 &modem_iface_1, 178 NULL, 179 }; 180 181 static const struct usb_temp_config_desc modem_config_desc = { 182 .ppIfaceDesc = modem_interfaces, 183 .bmAttributes = UC_BUS_POWERED, 184 .bMaxPower = 25, /* 50 mA */ 185 .iConfiguration = INDEX_PRODUCT, 186 }; 187 188 static const struct usb_temp_config_desc *modem_configs[] = { 189 &modem_config_desc, 190 NULL, 191 }; 192 193 static usb_temp_get_string_desc_t modem_get_string_desc; 194 static usb_temp_get_vendor_desc_t modem_get_vendor_desc; 195 196 const struct usb_temp_device_desc usb_template_modem = { 197 .getStringDesc = &modem_get_string_desc, 198 .getVendorDesc = &modem_get_vendor_desc, 199 .ppConfigDesc = modem_configs, 200 .idVendor = USB_TEMPLATE_VENDOR, 201 .idProduct = 0x000E, 202 .bcdDevice = 0x0100, 203 .bDeviceClass = UDCLASS_COMM, 204 .bDeviceSubClass = 0, 205 .bDeviceProtocol = 0, 206 .iManufacturer = 0, 207 .iProduct = INDEX_PRODUCT, 208 .iSerialNumber = 0, 209 }; 210 211 /*------------------------------------------------------------------------* 212 * modem_get_vendor_desc 213 * 214 * Return values: 215 * NULL: Failure. No such vendor descriptor. 216 * Else: Success. Pointer to vendor descriptor is returned. 217 *------------------------------------------------------------------------*/ 218 static const void * 219 modem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 220 { 221 return (NULL); 222 } 223 224 /*------------------------------------------------------------------------* 225 * modem_get_string_desc 226 * 227 * Return values: 228 * NULL: Failure. No such string. 229 * Else: Success. Pointer to string descriptor is returned. 230 *------------------------------------------------------------------------*/ 231 static const void * 232 modem_get_string_desc(uint16_t lang_id, uint8_t string_index) 233 { 234 static const void *ptr[INDEX_MAX] = { 235 [INDEX_LANG] = &usb_string_lang_en, 236 [INDEX_MODEM] = &string_modem, 237 [INDEX_PRODUCT] = &string_product, 238 }; 239 240 if (string_index == 0) { 241 return (&usb_string_lang_en); 242 } 243 if (lang_id != 0x0409) { 244 return (NULL); 245 } 246 if (string_index < INDEX_MAX) { 247 return (ptr[string_index]); 248 } 249 return (NULL); 250 } 251