1 /* $FreeBSD$ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2010 Hans Petter Selasky 6 * Copyright (c) 2018 The FreeBSD Foundation 7 * All rights reserved. 8 * 9 * Portions of this software were developed by Edward Tomasz Napierala 10 * under sponsorship from the FreeBSD Foundation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * This file contains the USB template for an USB Modem Device. 36 */ 37 38 #ifdef USB_GLOBAL_INCLUDE_FILE 39 #include USB_GLOBAL_INCLUDE_FILE 40 #else 41 #include <sys/stdint.h> 42 #include <sys/stddef.h> 43 #include <sys/param.h> 44 #include <sys/queue.h> 45 #include <sys/types.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/bus.h> 49 #include <sys/module.h> 50 #include <sys/lock.h> 51 #include <sys/mutex.h> 52 #include <sys/condvar.h> 53 #include <sys/sysctl.h> 54 #include <sys/sx.h> 55 #include <sys/unistd.h> 56 #include <sys/callout.h> 57 #include <sys/malloc.h> 58 #include <sys/priv.h> 59 60 #include <dev/usb/usb.h> 61 #include <dev/usb/usbdi.h> 62 #include <dev/usb/usb_core.h> 63 #include <dev/usb/usb_cdc.h> 64 #include <dev/usb/usb_ioctl.h> 65 #include <dev/usb/usb_util.h> 66 67 #include <dev/usb/template/usb_template.h> 68 #endif /* USB_GLOBAL_INCLUDE_FILE */ 69 70 enum { 71 MODEM_LANG_INDEX, 72 MODEM_INTERFACE_INDEX, 73 MODEM_MANUFACTURER_INDEX, 74 MODEM_PRODUCT_INDEX, 75 MODEM_SERIAL_NUMBER_INDEX, 76 MODEM_MAX_INDEX, 77 }; 78 79 #define MODEM_DEFAULT_VENDOR_ID USB_TEMPLATE_VENDOR 80 #define MODEM_DEFAULT_PRODUCT_ID 0x27dd 81 #define MODEM_DEFAULT_INTERFACE "Modem interface" 82 #define MODEM_DEFAULT_MANUFACTURER USB_TEMPLATE_MANUFACTURER 83 #define MODEM_DEFAULT_PRODUCT "Modem Test Device" 84 #define MODEM_DEFAULT_SERIAL_NUMBER "March 2008" 85 86 static struct usb_string_descriptor modem_interface; 87 static struct usb_string_descriptor modem_manufacturer; 88 static struct usb_string_descriptor modem_product; 89 static struct usb_string_descriptor modem_serial_number; 90 91 static struct sysctl_ctx_list modem_ctx_list; 92 93 #define MODEM_IFACE_0 0 94 #define MODEM_IFACE_1 1 95 96 /* prototypes */ 97 98 static const struct usb_temp_packet_size modem_bulk_mps = { 99 .mps[USB_SPEED_LOW] = 8, 100 .mps[USB_SPEED_FULL] = 64, 101 .mps[USB_SPEED_HIGH] = 512, 102 }; 103 104 static const struct usb_temp_packet_size modem_intr_mps = { 105 .mps[USB_SPEED_LOW] = 8, 106 .mps[USB_SPEED_FULL] = 8, 107 .mps[USB_SPEED_HIGH] = 8, 108 }; 109 110 static const struct usb_temp_interval modem_intr_interval = { 111 .bInterval[USB_SPEED_LOW] = 8, /* 8ms */ 112 .bInterval[USB_SPEED_FULL] = 8, /* 8ms */ 113 .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */ 114 }; 115 116 static const struct usb_temp_endpoint_desc modem_ep_0 = { 117 .pPacketSize = &modem_intr_mps, 118 .pIntervals = &modem_intr_interval, 119 .bEndpointAddress = UE_DIR_IN, 120 .bmAttributes = UE_INTERRUPT, 121 }; 122 123 static const struct usb_temp_endpoint_desc modem_ep_1 = { 124 .pPacketSize = &modem_bulk_mps, 125 .bEndpointAddress = UE_DIR_OUT, 126 .bmAttributes = UE_BULK, 127 }; 128 129 static const struct usb_temp_endpoint_desc modem_ep_2 = { 130 .pPacketSize = &modem_bulk_mps, 131 .bEndpointAddress = UE_DIR_IN, 132 .bmAttributes = UE_BULK, 133 }; 134 135 static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 136 &modem_ep_0, 137 NULL, 138 }; 139 140 static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 141 &modem_ep_1, 142 &modem_ep_2, 143 NULL, 144 }; 145 146 static const uint8_t modem_raw_desc_0[] = { 147 0x05, 0x24, 0x00, 0x10, 0x01 148 }; 149 150 static const uint8_t modem_raw_desc_1[] = { 151 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 152 }; 153 154 static const uint8_t modem_raw_desc_2[] = { 155 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 156 }; 157 158 static const uint8_t modem_raw_desc_3[] = { 159 0x04, 0x24, 0x02, 0x07 160 }; 161 162 static const void *modem_iface_0_desc[] = { 163 &modem_raw_desc_0, 164 &modem_raw_desc_1, 165 &modem_raw_desc_2, 166 &modem_raw_desc_3, 167 NULL, 168 }; 169 170 static const struct usb_temp_interface_desc modem_iface_0 = { 171 .ppRawDesc = modem_iface_0_desc, 172 .ppEndpoints = modem_iface_0_ep, 173 .bInterfaceClass = UICLASS_CDC, 174 .bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL, 175 .bInterfaceProtocol = UIPROTO_CDC_NONE, 176 .iInterface = MODEM_INTERFACE_INDEX, 177 }; 178 179 static const struct usb_temp_interface_desc modem_iface_1 = { 180 .ppEndpoints = modem_iface_1_ep, 181 .bInterfaceClass = UICLASS_CDC_DATA, 182 .bInterfaceSubClass = UISUBCLASS_DATA, 183 .bInterfaceProtocol = UIPROTO_CDC_NONE, 184 .iInterface = MODEM_INTERFACE_INDEX, 185 }; 186 187 static const struct usb_temp_interface_desc *modem_interfaces[] = { 188 &modem_iface_0, 189 &modem_iface_1, 190 NULL, 191 }; 192 193 static const struct usb_temp_config_desc modem_config_desc = { 194 .ppIfaceDesc = modem_interfaces, 195 .bmAttributes = UC_BUS_POWERED, 196 .bMaxPower = 25, /* 50 mA */ 197 .iConfiguration = MODEM_PRODUCT_INDEX, 198 }; 199 200 static const struct usb_temp_config_desc *modem_configs[] = { 201 &modem_config_desc, 202 NULL, 203 }; 204 205 static usb_temp_get_string_desc_t modem_get_string_desc; 206 static usb_temp_get_vendor_desc_t modem_get_vendor_desc; 207 208 struct usb_temp_device_desc usb_template_modem = { 209 .getStringDesc = &modem_get_string_desc, 210 .getVendorDesc = &modem_get_vendor_desc, 211 .ppConfigDesc = modem_configs, 212 .idVendor = MODEM_DEFAULT_VENDOR_ID, 213 .idProduct = MODEM_DEFAULT_PRODUCT_ID, 214 .bcdDevice = 0x0100, 215 .bDeviceClass = UDCLASS_COMM, 216 .bDeviceSubClass = 0, 217 .bDeviceProtocol = 0, 218 .iManufacturer = MODEM_MANUFACTURER_INDEX, 219 .iProduct = MODEM_PRODUCT_INDEX, 220 .iSerialNumber = MODEM_SERIAL_NUMBER_INDEX, 221 }; 222 223 /*------------------------------------------------------------------------* 224 * modem_get_vendor_desc 225 * 226 * Return values: 227 * NULL: Failure. No such vendor descriptor. 228 * Else: Success. Pointer to vendor descriptor is returned. 229 *------------------------------------------------------------------------*/ 230 static const void * 231 modem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 232 { 233 return (NULL); 234 } 235 236 /*------------------------------------------------------------------------* 237 * modem_get_string_desc 238 * 239 * Return values: 240 * NULL: Failure. No such string. 241 * Else: Success. Pointer to string descriptor is returned. 242 *------------------------------------------------------------------------*/ 243 static const void * 244 modem_get_string_desc(uint16_t lang_id, uint8_t string_index) 245 { 246 static const void *ptr[MODEM_MAX_INDEX] = { 247 [MODEM_LANG_INDEX] = &usb_string_lang_en, 248 [MODEM_INTERFACE_INDEX] = &modem_interface, 249 [MODEM_MANUFACTURER_INDEX] = &modem_manufacturer, 250 [MODEM_PRODUCT_INDEX] = &modem_product, 251 [MODEM_SERIAL_NUMBER_INDEX] = &modem_serial_number, 252 }; 253 254 if (string_index == 0) { 255 return (&usb_string_lang_en); 256 } 257 if (lang_id != 0x0409) { 258 return (NULL); 259 } 260 if (string_index < MODEM_MAX_INDEX) { 261 return (ptr[string_index]); 262 } 263 return (NULL); 264 } 265 266 static void 267 modem_init(void *arg __unused) 268 { 269 struct sysctl_oid *parent; 270 char parent_name[3]; 271 272 usb_make_str_desc(&modem_interface, sizeof(modem_interface), 273 MODEM_DEFAULT_INTERFACE); 274 usb_make_str_desc(&modem_manufacturer, sizeof(modem_manufacturer), 275 MODEM_DEFAULT_MANUFACTURER); 276 usb_make_str_desc(&modem_product, sizeof(modem_product), 277 MODEM_DEFAULT_PRODUCT); 278 usb_make_str_desc(&modem_serial_number, sizeof(modem_serial_number), 279 MODEM_DEFAULT_SERIAL_NUMBER); 280 281 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MODEM); 282 sysctl_ctx_init(&modem_ctx_list); 283 284 parent = SYSCTL_ADD_NODE(&modem_ctx_list, 285 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO, 286 parent_name, CTLFLAG_RW, 287 0, "USB Modem device side template"); 288 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 289 "vendor_id", CTLFLAG_RWTUN, 290 &usb_template_modem.idVendor, 1, "Vendor identifier"); 291 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 292 "product_id", CTLFLAG_RWTUN, 293 &usb_template_modem.idProduct, 1, "Product identifier"); 294 #if 0 295 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 296 "keyboard", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 297 &modem_interface, sizeof(modem_interface), usb_temp_sysctl, 298 "A", "Interface string"); 299 #endif 300 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 301 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 302 &modem_manufacturer, sizeof(modem_manufacturer), usb_temp_sysctl, 303 "A", "Manufacturer string"); 304 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 305 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 306 &modem_product, sizeof(modem_product), usb_temp_sysctl, 307 "A", "Product string"); 308 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 309 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 310 &modem_serial_number, sizeof(modem_serial_number), usb_temp_sysctl, 311 "A", "Serial number string"); 312 } 313 314 static void 315 modem_uninit(void *arg __unused) 316 { 317 318 sysctl_ctx_free(&modem_ctx_list); 319 } 320 321 SYSINIT(modem_init, SI_SUB_LOCK, SI_ORDER_FIRST, modem_init, NULL); 322 SYSUNINIT(modem_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, modem_uninit, NULL); 323