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_INTERFACE "Modem interface" 80 #define MODEM_DEFAULT_MANUFACTURER "FreeBSD foundation" 81 #define MODEM_DEFAULT_PRODUCT "Modem Test Device" 82 #define MODEM_DEFAULT_SERIAL_NUMBER "March 2008" 83 84 static struct usb_string_descriptor modem_interface; 85 static struct usb_string_descriptor modem_manufacturer; 86 static struct usb_string_descriptor modem_product; 87 static struct usb_string_descriptor modem_serial_number; 88 89 static struct sysctl_ctx_list modem_ctx_list; 90 91 #define MODEM_IFACE_0 0 92 #define MODEM_IFACE_1 1 93 94 /* prototypes */ 95 96 static const struct usb_temp_packet_size modem_bulk_mps = { 97 .mps[USB_SPEED_LOW] = 8, 98 .mps[USB_SPEED_FULL] = 64, 99 .mps[USB_SPEED_HIGH] = 512, 100 }; 101 102 static const struct usb_temp_packet_size modem_intr_mps = { 103 .mps[USB_SPEED_LOW] = 8, 104 .mps[USB_SPEED_FULL] = 8, 105 .mps[USB_SPEED_HIGH] = 8, 106 }; 107 108 static const struct usb_temp_interval modem_intr_interval = { 109 .bInterval[USB_SPEED_LOW] = 8, /* 8ms */ 110 .bInterval[USB_SPEED_FULL] = 8, /* 8ms */ 111 .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */ 112 }; 113 114 static const struct usb_temp_endpoint_desc modem_ep_0 = { 115 .pPacketSize = &modem_intr_mps, 116 .pIntervals = &modem_intr_interval, 117 .bEndpointAddress = UE_DIR_IN, 118 .bmAttributes = UE_INTERRUPT, 119 }; 120 121 static const struct usb_temp_endpoint_desc modem_ep_1 = { 122 .pPacketSize = &modem_bulk_mps, 123 .bEndpointAddress = UE_DIR_OUT, 124 .bmAttributes = UE_BULK, 125 }; 126 127 static const struct usb_temp_endpoint_desc modem_ep_2 = { 128 .pPacketSize = &modem_bulk_mps, 129 .bEndpointAddress = UE_DIR_IN, 130 .bmAttributes = UE_BULK, 131 }; 132 133 static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { 134 &modem_ep_0, 135 NULL, 136 }; 137 138 static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { 139 &modem_ep_1, 140 &modem_ep_2, 141 NULL, 142 }; 143 144 static const uint8_t modem_raw_desc_0[] = { 145 0x05, 0x24, 0x00, 0x10, 0x01 146 }; 147 148 static const uint8_t modem_raw_desc_1[] = { 149 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 150 }; 151 152 static const uint8_t modem_raw_desc_2[] = { 153 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 154 }; 155 156 static const uint8_t modem_raw_desc_3[] = { 157 0x04, 0x24, 0x02, 0x07 158 }; 159 160 static const void *modem_iface_0_desc[] = { 161 &modem_raw_desc_0, 162 &modem_raw_desc_1, 163 &modem_raw_desc_2, 164 &modem_raw_desc_3, 165 NULL, 166 }; 167 168 static const struct usb_temp_interface_desc modem_iface_0 = { 169 .ppRawDesc = modem_iface_0_desc, 170 .ppEndpoints = modem_iface_0_ep, 171 .bInterfaceClass = UICLASS_CDC, 172 .bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL, 173 .bInterfaceProtocol = UIPROTO_CDC_NONE, 174 .iInterface = MODEM_INTERFACE_INDEX, 175 }; 176 177 static const struct usb_temp_interface_desc modem_iface_1 = { 178 .ppEndpoints = modem_iface_1_ep, 179 .bInterfaceClass = UICLASS_CDC_DATA, 180 .bInterfaceSubClass = UISUBCLASS_DATA, 181 .bInterfaceProtocol = UIPROTO_CDC_NONE, 182 .iInterface = MODEM_INTERFACE_INDEX, 183 }; 184 185 static const struct usb_temp_interface_desc *modem_interfaces[] = { 186 &modem_iface_0, 187 &modem_iface_1, 188 NULL, 189 }; 190 191 static const struct usb_temp_config_desc modem_config_desc = { 192 .ppIfaceDesc = modem_interfaces, 193 .bmAttributes = UC_BUS_POWERED, 194 .bMaxPower = 25, /* 50 mA */ 195 .iConfiguration = MODEM_PRODUCT_INDEX, 196 }; 197 198 static const struct usb_temp_config_desc *modem_configs[] = { 199 &modem_config_desc, 200 NULL, 201 }; 202 203 static usb_temp_get_string_desc_t modem_get_string_desc; 204 static usb_temp_get_vendor_desc_t modem_get_vendor_desc; 205 206 struct usb_temp_device_desc usb_template_modem = { 207 .getStringDesc = &modem_get_string_desc, 208 .getVendorDesc = &modem_get_vendor_desc, 209 .ppConfigDesc = modem_configs, 210 .idVendor = USB_TEMPLATE_VENDOR, 211 .idProduct = 0x000E, 212 .bcdDevice = 0x0100, 213 .bDeviceClass = UDCLASS_COMM, 214 .bDeviceSubClass = 0, 215 .bDeviceProtocol = 0, 216 .iManufacturer = MODEM_MANUFACTURER_INDEX, 217 .iProduct = MODEM_PRODUCT_INDEX, 218 .iSerialNumber = MODEM_SERIAL_NUMBER_INDEX, 219 }; 220 221 /*------------------------------------------------------------------------* 222 * modem_get_vendor_desc 223 * 224 * Return values: 225 * NULL: Failure. No such vendor descriptor. 226 * Else: Success. Pointer to vendor descriptor is returned. 227 *------------------------------------------------------------------------*/ 228 static const void * 229 modem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 230 { 231 return (NULL); 232 } 233 234 /*------------------------------------------------------------------------* 235 * modem_get_string_desc 236 * 237 * Return values: 238 * NULL: Failure. No such string. 239 * Else: Success. Pointer to string descriptor is returned. 240 *------------------------------------------------------------------------*/ 241 static const void * 242 modem_get_string_desc(uint16_t lang_id, uint8_t string_index) 243 { 244 static const void *ptr[MODEM_MAX_INDEX] = { 245 [MODEM_LANG_INDEX] = &usb_string_lang_en, 246 [MODEM_INTERFACE_INDEX] = &modem_interface, 247 [MODEM_MANUFACTURER_INDEX] = &modem_manufacturer, 248 [MODEM_PRODUCT_INDEX] = &modem_product, 249 [MODEM_SERIAL_NUMBER_INDEX] = &modem_serial_number, 250 }; 251 252 if (string_index == 0) { 253 return (&usb_string_lang_en); 254 } 255 if (lang_id != 0x0409) { 256 return (NULL); 257 } 258 if (string_index < MODEM_MAX_INDEX) { 259 return (ptr[string_index]); 260 } 261 return (NULL); 262 } 263 264 static void 265 modem_init(void *arg __unused) 266 { 267 struct sysctl_oid *parent; 268 char parent_name[3]; 269 270 usb_make_str_desc(&modem_interface, sizeof(modem_interface), 271 MODEM_DEFAULT_INTERFACE); 272 usb_make_str_desc(&modem_manufacturer, sizeof(modem_manufacturer), 273 MODEM_DEFAULT_MANUFACTURER); 274 usb_make_str_desc(&modem_product, sizeof(modem_product), 275 MODEM_DEFAULT_PRODUCT); 276 usb_make_str_desc(&modem_serial_number, sizeof(modem_serial_number), 277 MODEM_DEFAULT_SERIAL_NUMBER); 278 279 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MODEM); 280 sysctl_ctx_init(&modem_ctx_list); 281 282 parent = SYSCTL_ADD_NODE(&modem_ctx_list, 283 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO, 284 parent_name, CTLFLAG_RW, 285 0, "USB Modem device side template"); 286 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 287 "vendor_id", CTLFLAG_RWTUN, 288 &usb_template_modem.idVendor, 1, "Vendor identifier"); 289 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 290 "product_id", CTLFLAG_RWTUN, 291 &usb_template_modem.idProduct, 1, "Product identifier"); 292 #if 0 293 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 294 "keyboard", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 295 &modem_interface, sizeof(modem_interface), usb_temp_sysctl, 296 "A", "Interface string"); 297 #endif 298 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 299 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 300 &modem_manufacturer, sizeof(modem_manufacturer), usb_temp_sysctl, 301 "A", "Manufacturer string"); 302 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 303 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 304 &modem_product, sizeof(modem_product), usb_temp_sysctl, 305 "A", "Product string"); 306 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 307 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 308 &modem_serial_number, sizeof(modem_serial_number), usb_temp_sysctl, 309 "A", "Serial number string"); 310 } 311 312 static void 313 modem_uninit(void *arg __unused) 314 { 315 316 sysctl_ctx_free(&modem_ctx_list); 317 } 318 319 SYSINIT(modem_init, SI_SUB_LOCK, SI_ORDER_FIRST, modem_init, NULL); 320 SYSUNINIT(modem_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, modem_uninit, NULL); 321