1 /*- 2 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD: head/sys/dev/usb/gadget/g_modem.c 253618 2013-07-24 18:32:15Z obrien $ 26 */ 27 28 /* 29 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf 30 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 31 * http://www.usb.org/developers/devclass_docs/cdc_wmc10.zip 32 */ 33 34 #include <sys/stdint.h> 35 #include <sys/queue.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/bus.h> 39 #include <sys/linker_set.h> 40 #include <sys/module.h> 41 #include <sys/lock.h> 42 #include <sys/condvar.h> 43 #include <sys/sysctl.h> 44 #include <sys/unistd.h> 45 #include <sys/callout.h> 46 #include <sys/malloc.h> 47 #include <sys/priv.h> 48 49 #include <bus/u4b/usb.h> 50 #include <bus/u4b/usb_cdc.h> 51 #include <bus/u4b/usbdi.h> 52 #include <bus/u4b/usbdi_util.h> 53 #include <bus/u4b/usbhid.h> 54 #include "usb_if.h" 55 56 #define USB_DEBUG_VAR g_modem_debug 57 #include <bus/u4b/usb_debug.h> 58 59 #include <bus/u4b/gadget/g_modem.h> 60 61 enum { 62 G_MODEM_INTR_DT, 63 G_MODEM_BULK_RD, 64 G_MODEM_BULK_WR, 65 G_MODEM_N_TRANSFER, 66 }; 67 68 struct g_modem_softc { 69 struct lock sc_lock; 70 struct usb_callout sc_callout; 71 struct usb_callout sc_watchdog; 72 struct usb_xfer *sc_xfer[G_MODEM_N_TRANSFER]; 73 74 int sc_mode; 75 int sc_tx_busy; 76 int sc_pattern_len; 77 int sc_throughput; 78 int sc_tx_interval; 79 80 char sc_pattern[G_MODEM_MAX_STRLEN]; 81 82 uint16_t sc_data_len; 83 84 uint8_t sc_data_buf[G_MODEM_BUFSIZE]; 85 uint8_t sc_line_coding[32]; 86 uint8_t sc_abstract_state[32]; 87 }; 88 89 static SYSCTL_NODE(_hw_usb, OID_AUTO, g_modem, CTLFLAG_RW, 0, "USB modem gadget"); 90 91 #ifdef USB_DEBUG 92 static int g_modem_debug = 0; 93 94 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, debug, CTLFLAG_RW, 95 &g_modem_debug, 0, "Debug level"); 96 #endif 97 98 static int g_modem_mode = 0; 99 100 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, mode, CTLFLAG_RW, 101 &g_modem_mode, 0, "Mode selection"); 102 103 static int g_modem_pattern_interval = 1000; 104 105 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, pattern_interval, CTLFLAG_RW, 106 &g_modem_pattern_interval, 0, "Pattern interval in milliseconds"); 107 108 static char g_modem_pattern_data[G_MODEM_MAX_STRLEN]; 109 110 SYSCTL_STRING(_hw_usb_g_modem, OID_AUTO, pattern, CTLFLAG_RW, 111 &g_modem_pattern_data, sizeof(g_modem_pattern_data), "Data pattern"); 112 113 static int g_modem_throughput; 114 115 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, throughput, CTLFLAG_RD, 116 &g_modem_throughput, sizeof(g_modem_throughput), "Throughput in bytes per second"); 117 118 static device_probe_t g_modem_probe; 119 static device_attach_t g_modem_attach; 120 static device_detach_t g_modem_detach; 121 static usb_handle_request_t g_modem_handle_request; 122 static usb_callback_t g_modem_intr_callback; 123 static usb_callback_t g_modem_bulk_read_callback; 124 static usb_callback_t g_modem_bulk_write_callback; 125 126 static void g_modem_timeout(void *arg); 127 128 static devclass_t g_modem_devclass; 129 130 static device_method_t g_modem_methods[] = { 131 /* USB interface */ 132 DEVMETHOD(usb_handle_request, g_modem_handle_request), 133 134 /* Device interface */ 135 DEVMETHOD(device_probe, g_modem_probe), 136 DEVMETHOD(device_attach, g_modem_attach), 137 DEVMETHOD(device_detach, g_modem_detach), 138 139 DEVMETHOD_END 140 }; 141 142 static driver_t g_modem_driver = { 143 .name = "g_modem", 144 .methods = g_modem_methods, 145 .size = sizeof(struct g_modem_softc), 146 }; 147 148 DRIVER_MODULE(g_modem, uhub, g_modem_driver, g_modem_devclass, NULL, NULL); 149 MODULE_DEPEND(g_modem, usb, 1, 1, 1); 150 151 static const struct usb_config g_modem_config[G_MODEM_N_TRANSFER] = { 152 153 [G_MODEM_INTR_DT] = { 154 .type = UE_INTERRUPT, 155 .endpoint = UE_ADDR_ANY, 156 .direction = UE_DIR_TX, 157 .flags = {.ext_buffer = 1,.pipe_bof = 1,}, 158 .bufsize = 0, /* use wMaxPacketSize */ 159 .callback = &g_modem_intr_callback, 160 .frames = 1, 161 .usb_mode = USB_MODE_DEVICE, 162 .if_index = 0, 163 }, 164 165 [G_MODEM_BULK_RD] = { 166 .type = UE_BULK, 167 .endpoint = UE_ADDR_ANY, 168 .direction = UE_DIR_RX, 169 .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,}, 170 .bufsize = G_MODEM_BUFSIZE, 171 .callback = &g_modem_bulk_read_callback, 172 .frames = 1, 173 .usb_mode = USB_MODE_DEVICE, 174 .if_index = 1, 175 }, 176 177 [G_MODEM_BULK_WR] = { 178 .type = UE_BULK, 179 .endpoint = UE_ADDR_ANY, 180 .direction = UE_DIR_TX, 181 .flags = {.ext_buffer = 1,.pipe_bof = 1,}, 182 .bufsize = G_MODEM_BUFSIZE, 183 .callback = &g_modem_bulk_write_callback, 184 .frames = 1, 185 .usb_mode = USB_MODE_DEVICE, 186 .if_index = 1, 187 }, 188 }; 189 190 static void 191 g_modem_timeout_reset(struct g_modem_softc *sc) 192 { 193 int i = g_modem_pattern_interval; 194 195 sc->sc_tx_interval = i; 196 197 if (i <= 0) 198 i = 1; 199 else if (i > 1023) 200 i = 1023; 201 202 i = USB_MS_TO_TICKS(i); 203 204 usb_callout_reset(&sc->sc_callout, i, &g_modem_timeout, sc); 205 } 206 207 static void 208 g_modem_timeout(void *arg) 209 { 210 struct g_modem_softc *sc = arg; 211 212 sc->sc_mode = g_modem_mode; 213 214 memcpy(sc->sc_pattern, g_modem_pattern_data, sizeof(sc->sc_pattern)); 215 216 sc->sc_pattern[G_MODEM_MAX_STRLEN - 1] = 0; 217 218 sc->sc_pattern_len = strlen(sc->sc_pattern); 219 220 DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_MODEM_INTR_DT]); 221 222 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]); 223 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]); 224 225 g_modem_timeout_reset(sc); 226 } 227 228 static void g_modem_watchdog(void *arg); 229 230 static void 231 g_modem_watchdog_reset(struct g_modem_softc *sc) 232 { 233 usb_callout_reset(&sc->sc_watchdog, hz, &g_modem_watchdog, sc); 234 } 235 236 static void 237 g_modem_watchdog(void *arg) 238 { 239 struct g_modem_softc *sc = arg; 240 int i; 241 242 i = sc->sc_throughput; 243 244 sc->sc_throughput = 0; 245 246 g_modem_throughput = i; 247 248 g_modem_watchdog_reset(sc); 249 } 250 251 static int 252 g_modem_probe(device_t dev) 253 { 254 struct usb_attach_arg *uaa = device_get_ivars(dev); 255 256 DPRINTFN(11, "\n"); 257 258 if (uaa->usb_mode != USB_MODE_DEVICE) 259 return (ENXIO); 260 261 if ((uaa->info.bInterfaceClass == UICLASS_CDC) && 262 (uaa->info.bInterfaceSubClass == UISUBCLASS_ABSTRACT_CONTROL_MODEL) && 263 (uaa->info.bInterfaceProtocol == UIPROTO_CDC_AT)) 264 return (0); 265 266 return (ENXIO); 267 } 268 269 static int 270 g_modem_attach(device_t dev) 271 { 272 struct g_modem_softc *sc = device_get_softc(dev); 273 struct usb_attach_arg *uaa = device_get_ivars(dev); 274 int error; 275 uint8_t iface_index[2]; 276 277 DPRINTFN(11, "\n"); 278 279 device_set_usb_desc(dev); 280 281 lockinit(&sc->sc_lock, "g_modem", 0, 0); 282 283 usb_callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0); 284 usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0); 285 286 sc->sc_mode = G_MODEM_MODE_SILENT; 287 288 iface_index[0] = uaa->info.bIfaceIndex; 289 iface_index[1] = uaa->info.bIfaceIndex + 1; 290 291 error = usbd_transfer_setup(uaa->device, 292 iface_index, sc->sc_xfer, g_modem_config, 293 G_MODEM_N_TRANSFER, sc, &sc->sc_lock); 294 295 if (error) { 296 DPRINTF("error=%s\n", usbd_errstr(error)); 297 goto detach; 298 } 299 usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]); 300 301 lockmgr(&sc->sc_lock, LK_EXCLUSIVE); 302 g_modem_timeout_reset(sc); 303 g_modem_watchdog_reset(sc); 304 lockmgr(&sc->sc_lock, LK_RELEASE); 305 306 return (0); /* success */ 307 308 detach: 309 g_modem_detach(dev); 310 311 return (ENXIO); /* error */ 312 } 313 314 static int 315 g_modem_detach(device_t dev) 316 { 317 struct g_modem_softc *sc = device_get_softc(dev); 318 319 DPRINTF("\n"); 320 321 lockmgr(&sc->sc_lock, LK_EXCLUSIVE); 322 usb_callout_stop(&sc->sc_callout); 323 usb_callout_stop(&sc->sc_watchdog); 324 lockmgr(&sc->sc_lock, LK_RELEASE); 325 326 usbd_transfer_unsetup(sc->sc_xfer, G_MODEM_N_TRANSFER); 327 328 usb_callout_drain(&sc->sc_callout); 329 usb_callout_drain(&sc->sc_watchdog); 330 331 lockuninit(&sc->sc_lock); 332 333 return (0); 334 } 335 336 static void 337 g_modem_intr_callback(struct usb_xfer *xfer, usb_error_t error) 338 { 339 int actlen; 340 int aframes; 341 342 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 343 344 DPRINTF("st=%d aframes=%d actlen=%d bytes\n", 345 USB_GET_STATE(xfer), aframes, actlen); 346 347 switch (USB_GET_STATE(xfer)) { 348 case USB_ST_TRANSFERRED: 349 break; 350 351 case USB_ST_SETUP: 352 tr_setup: 353 break; 354 355 default: /* Error */ 356 DPRINTF("error=%s\n", usbd_errstr(error)); 357 358 if (error != USB_ERR_CANCELLED) { 359 /* try to clear stall first */ 360 usbd_xfer_set_stall(xfer); 361 goto tr_setup; 362 } 363 break; 364 } 365 } 366 367 static void 368 g_modem_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 369 { 370 struct g_modem_softc *sc = usbd_xfer_softc(xfer); 371 int actlen; 372 int aframes; 373 int mod; 374 int x; 375 int max; 376 377 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 378 379 DPRINTF("st=%d aframes=%d actlen=%d bytes\n", 380 USB_GET_STATE(xfer), aframes, actlen); 381 382 switch (USB_GET_STATE(xfer)) { 383 case USB_ST_TRANSFERRED: 384 385 sc->sc_tx_busy = 0; 386 sc->sc_throughput += actlen; 387 388 if (sc->sc_mode == G_MODEM_MODE_LOOP) { 389 /* start loop */ 390 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]); 391 break; 392 } else if ((sc->sc_mode == G_MODEM_MODE_PATTERN) && (sc->sc_tx_interval != 0)) { 393 /* wait for next timeout */ 394 break; 395 } 396 case USB_ST_SETUP: 397 tr_setup: 398 if (sc->sc_mode == G_MODEM_MODE_PATTERN) { 399 400 mod = sc->sc_pattern_len; 401 max = sc->sc_tx_interval ? mod : G_MODEM_BUFSIZE; 402 403 if (mod == 0) { 404 for (x = 0; x != max; x++) 405 sc->sc_data_buf[x] = x % 255; 406 } else { 407 for (x = 0; x != max; x++) 408 sc->sc_data_buf[x] = sc->sc_pattern[x % mod]; 409 } 410 411 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, max); 412 usbd_xfer_set_interval(xfer, 0); 413 usbd_xfer_set_frames(xfer, 1); 414 usbd_transfer_submit(xfer); 415 416 } else if (sc->sc_mode == G_MODEM_MODE_LOOP) { 417 418 if (sc->sc_tx_busy == 0) 419 break; 420 421 x = sc->sc_tx_interval; 422 423 if (x < 0) 424 x = 0; 425 else if (x > 256) 426 x = 256; 427 428 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, sc->sc_data_len); 429 usbd_xfer_set_interval(xfer, x); 430 usbd_xfer_set_frames(xfer, 1); 431 usbd_transfer_submit(xfer); 432 } else { 433 sc->sc_tx_busy = 0; 434 } 435 break; 436 437 default: /* Error */ 438 DPRINTF("error=%s\n", usbd_errstr(error)); 439 440 if (error != USB_ERR_CANCELLED) { 441 /* try to clear stall first */ 442 usbd_xfer_set_stall(xfer); 443 goto tr_setup; 444 } 445 break; 446 } 447 } 448 449 static void 450 g_modem_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 451 { 452 struct g_modem_softc *sc = usbd_xfer_softc(xfer); 453 int actlen; 454 int aframes; 455 456 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 457 458 DPRINTF("st=%d aframes=%d actlen=%d bytes\n", 459 USB_GET_STATE(xfer), aframes, actlen); 460 461 switch (USB_GET_STATE(xfer)) { 462 case USB_ST_TRANSFERRED: 463 464 sc->sc_throughput += actlen; 465 466 if (sc->sc_mode == G_MODEM_MODE_LOOP) { 467 sc->sc_tx_busy = 1; 468 sc->sc_data_len = actlen; 469 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]); 470 break; 471 } 472 473 case USB_ST_SETUP: 474 tr_setup: 475 if ((sc->sc_mode == G_MODEM_MODE_SILENT) || 476 (sc->sc_tx_busy != 0)) 477 break; 478 479 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, G_MODEM_BUFSIZE); 480 usbd_xfer_set_frames(xfer, 1); 481 usbd_transfer_submit(xfer); 482 break; 483 484 default: /* Error */ 485 DPRINTF("error=%s\n", usbd_errstr(error)); 486 487 if (error != USB_ERR_CANCELLED) { 488 /* try to clear stall first */ 489 usbd_xfer_set_stall(xfer); 490 goto tr_setup; 491 } 492 break; 493 } 494 } 495 496 497 static int 498 g_modem_handle_request(device_t dev, 499 const void *preq, void **pptr, uint16_t *plen, 500 uint16_t offset, uint8_t *pstate) 501 { 502 struct g_modem_softc *sc = device_get_softc(dev); 503 const struct usb_device_request *req = preq; 504 uint8_t is_complete = *pstate; 505 506 if (!is_complete) { 507 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 508 (req->bRequest == UCDC_SET_LINE_CODING) && 509 (req->wValue[0] == 0x00) && 510 (req->wValue[1] == 0x00)) { 511 512 if (offset == 0) { 513 *plen = sizeof(sc->sc_line_coding); 514 *pptr = &sc->sc_line_coding; 515 } else { 516 *plen = 0; 517 } 518 return (0); 519 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 520 (req->bRequest == UCDC_SET_COMM_FEATURE)) { 521 522 if (offset == 0) { 523 *plen = sizeof(sc->sc_abstract_state); 524 *pptr = &sc->sc_abstract_state; 525 } else { 526 *plen = 0; 527 } 528 return (0); 529 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 530 (req->bRequest == UCDC_SET_CONTROL_LINE_STATE)) { 531 *plen = 0; 532 return (0); 533 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 534 (req->bRequest == UCDC_SEND_BREAK)) { 535 *plen = 0; 536 return (0); 537 } 538 } 539 return (ENXIO); /* use builtin handler */ 540 } 541