1 /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */ 2 3 #include <sys/cdefs.h> 4 __FBSDID("$FreeBSD$"); 5 #define UFOMA_HANDSFREE 6 /*- 7 * Copyright (c) 2005, Takanori Watanabe 8 * Copyright (c) 2003, M. Warner Losh <imp@FreeBSD.org>. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1998 The NetBSD Foundation, Inc. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to The NetBSD Foundation 38 * by Lennart Augustsson (lennart@augustsson.net) at 39 * Carlstedt Research & Technology. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the NetBSD 52 * Foundation, Inc. and its contributors. 53 * 4. Neither the name of The NetBSD Foundation nor the names of its 54 * contributors may be used to endorse or promote products derived 55 * from this software without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 58 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 60 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 61 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 62 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 63 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 66 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 67 * POSSIBILITY OF SUCH DAMAGE. 68 */ 69 70 /* 71 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf 72 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 73 */ 74 75 /* 76 * TODO: 77 * - Implement a Call Device for modems without multiplexed commands. 78 */ 79 80 /* 81 * NOTE: all function names beginning like "ufoma_cfg_" can only 82 * be called from within the config thread function ! 83 */ 84 85 #include "usbdevs.h" 86 #include <dev/usb/usb.h> 87 #include <dev/usb/usb_mfunc.h> 88 #include <dev/usb/usb_error.h> 89 #include <dev/usb/usb_cdc.h> 90 91 #define USB_DEBUG_VAR usb2_debug 92 93 #include <dev/usb/usb_core.h> 94 #include <dev/usb/usb_debug.h> 95 #include <dev/usb/usb_process.h> 96 #include <dev/usb/usb_request.h> 97 #include <dev/usb/usb_lookup.h> 98 #include <dev/usb/usb_util.h> 99 #include <dev/usb/usb_parse.h> 100 #include <dev/usb/usb_busdma.h> 101 102 #include <dev/usb/serial/usb_serial.h> 103 #include <sys/sysctl.h> 104 #include <sys/sbuf.h> 105 106 typedef struct ufoma_mobile_acm_descriptor { 107 uint8_t bFunctionLength; 108 uint8_t bDescriptorType; 109 uint8_t bDescriptorSubtype; 110 uint8_t bType; 111 uint8_t bMode[1]; 112 } __packed usb2_mcpc_acm_descriptor; 113 114 #define UISUBCLASS_MCPC 0x88 115 116 #define UDESC_VS_INTERFACE 0x44 117 #define UDESCSUB_MCPC_ACM 0x11 118 119 #define UMCPC_ACM_TYPE_AB1 0x1 120 #define UMCPC_ACM_TYPE_AB2 0x2 121 #define UMCPC_ACM_TYPE_AB5 0x5 122 #define UMCPC_ACM_TYPE_AB6 0x6 123 124 #define UMCPC_ACM_MODE_DEACTIVATED 0x0 125 #define UMCPC_ACM_MODE_MODEM 0x1 126 #define UMCPC_ACM_MODE_ATCOMMAND 0x2 127 #define UMCPC_ACM_MODE_OBEX 0x60 128 #define UMCPC_ACM_MODE_VENDOR1 0xc0 129 #define UMCPC_ACM_MODE_VENDOR2 0xfe 130 #define UMCPC_ACM_MODE_UNLINKED 0xff 131 132 #define UMCPC_CM_MOBILE_ACM 0x0 133 134 #define UMCPC_ACTIVATE_MODE 0x60 135 #define UMCPC_GET_MODETABLE 0x61 136 #define UMCPC_SET_LINK 0x62 137 #define UMCPC_CLEAR_LINK 0x63 138 139 #define UMCPC_REQUEST_ACKNOWLEDGE 0x31 140 141 #define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */ 142 #define UFOMA_CMD_BUF_SIZE 64 /* bytes */ 143 144 #define UFOMA_BULK_BUF_SIZE 1024 /* bytes */ 145 146 enum { 147 UFOMA_CTRL_ENDPT_INTR, 148 UFOMA_CTRL_ENDPT_READ, 149 UFOMA_CTRL_ENDPT_WRITE, 150 UFOMA_CTRL_ENDPT_MAX, 151 }; 152 153 enum { 154 UFOMA_BULK_ENDPT_WRITE, 155 UFOMA_BULK_ENDPT_READ, 156 UFOMA_BULK_ENDPT_MAX, 157 }; 158 159 struct ufoma_softc { 160 struct usb2_com_super_softc sc_super_ucom; 161 struct usb2_com_softc sc_ucom; 162 struct cv sc_cv; 163 struct mtx sc_mtx; 164 165 struct usb2_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX]; 166 struct usb2_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX]; 167 uint8_t *sc_modetable; 168 device_t sc_dev; 169 struct usb2_device *sc_udev; 170 171 uint32_t sc_unit; 172 173 uint16_t sc_line; 174 175 uint8_t sc_num_msg; 176 uint8_t sc_nobulk; 177 uint8_t sc_ctrl_iface_no; 178 uint8_t sc_ctrl_iface_index; 179 uint8_t sc_data_iface_no; 180 uint8_t sc_data_iface_index; 181 uint8_t sc_cm_cap; 182 uint8_t sc_acm_cap; 183 uint8_t sc_lsr; 184 uint8_t sc_msr; 185 uint8_t sc_modetoactivate; 186 uint8_t sc_currentmode; 187 uint8_t sc_name[16]; 188 }; 189 190 /* prototypes */ 191 192 static device_probe_t ufoma_probe; 193 static device_attach_t ufoma_attach; 194 static device_detach_t ufoma_detach; 195 196 static usb2_callback_t ufoma_ctrl_read_callback; 197 static usb2_callback_t ufoma_ctrl_write_callback; 198 static usb2_callback_t ufoma_intr_callback; 199 static usb2_callback_t ufoma_bulk_write_callback; 200 static usb2_callback_t ufoma_bulk_read_callback; 201 202 static void *ufoma_get_intconf(struct usb2_config_descriptor *, 203 struct usb2_interface_descriptor *, uint8_t, uint8_t); 204 static void ufoma_cfg_link_state(struct ufoma_softc *); 205 static void ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t); 206 static void ufoma_cfg_open(struct usb2_com_softc *); 207 static void ufoma_cfg_close(struct usb2_com_softc *); 208 static void ufoma_cfg_set_break(struct usb2_com_softc *, uint8_t); 209 static void ufoma_cfg_get_status(struct usb2_com_softc *, uint8_t *, 210 uint8_t *); 211 static void ufoma_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 212 static void ufoma_cfg_set_rts(struct usb2_com_softc *, uint8_t); 213 static int ufoma_pre_param(struct usb2_com_softc *, struct termios *); 214 static void ufoma_cfg_param(struct usb2_com_softc *, struct termios *); 215 static int ufoma_modem_setup(device_t, struct ufoma_softc *, 216 struct usb2_attach_arg *); 217 static void ufoma_start_read(struct usb2_com_softc *); 218 static void ufoma_stop_read(struct usb2_com_softc *); 219 static void ufoma_start_write(struct usb2_com_softc *); 220 static void ufoma_stop_write(struct usb2_com_softc *); 221 222 /*sysctl stuff*/ 223 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS); 224 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS); 225 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS); 226 227 228 static const struct usb2_config 229 ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = { 230 231 [UFOMA_CTRL_ENDPT_INTR] = { 232 .type = UE_INTERRUPT, 233 .endpoint = UE_ADDR_ANY, 234 .direction = UE_DIR_IN, 235 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 236 .mh.bufsize = sizeof(struct usb2_cdc_notification), 237 .mh.callback = &ufoma_intr_callback, 238 }, 239 240 [UFOMA_CTRL_ENDPT_READ] = { 241 .type = UE_CONTROL, 242 .endpoint = 0x00, /* Control pipe */ 243 .direction = UE_DIR_ANY, 244 .mh.bufsize = (sizeof(struct usb2_device_request) + UFOMA_CMD_BUF_SIZE), 245 .mh.flags = {.short_xfer_ok = 1,}, 246 .mh.callback = &ufoma_ctrl_read_callback, 247 .mh.timeout = 1000, /* 1 second */ 248 }, 249 250 [UFOMA_CTRL_ENDPT_WRITE] = { 251 .type = UE_CONTROL, 252 .endpoint = 0x00, /* Control pipe */ 253 .direction = UE_DIR_ANY, 254 .mh.bufsize = (sizeof(struct usb2_device_request) + 1), 255 .mh.callback = &ufoma_ctrl_write_callback, 256 .mh.timeout = 1000, /* 1 second */ 257 }, 258 }; 259 260 static const struct usb2_config 261 ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = { 262 263 [UFOMA_BULK_ENDPT_WRITE] = { 264 .type = UE_BULK, 265 .endpoint = UE_ADDR_ANY, 266 .direction = UE_DIR_OUT, 267 .mh.bufsize = UFOMA_BULK_BUF_SIZE, 268 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 269 .mh.callback = &ufoma_bulk_write_callback, 270 }, 271 272 [UFOMA_BULK_ENDPT_READ] = { 273 .type = UE_BULK, 274 .endpoint = UE_ADDR_ANY, 275 .direction = UE_DIR_IN, 276 .mh.bufsize = UFOMA_BULK_BUF_SIZE, 277 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 278 .mh.callback = &ufoma_bulk_read_callback, 279 }, 280 }; 281 282 static const struct usb2_com_callback ufoma_callback = { 283 .usb2_com_cfg_get_status = &ufoma_cfg_get_status, 284 .usb2_com_cfg_set_dtr = &ufoma_cfg_set_dtr, 285 .usb2_com_cfg_set_rts = &ufoma_cfg_set_rts, 286 .usb2_com_cfg_set_break = &ufoma_cfg_set_break, 287 .usb2_com_cfg_param = &ufoma_cfg_param, 288 .usb2_com_cfg_open = &ufoma_cfg_open, 289 .usb2_com_cfg_close = &ufoma_cfg_close, 290 .usb2_com_pre_param = &ufoma_pre_param, 291 .usb2_com_start_read = &ufoma_start_read, 292 .usb2_com_stop_read = &ufoma_stop_read, 293 .usb2_com_start_write = &ufoma_start_write, 294 .usb2_com_stop_write = &ufoma_stop_write, 295 }; 296 297 static device_method_t ufoma_methods[] = { 298 /* Device methods */ 299 DEVMETHOD(device_probe, ufoma_probe), 300 DEVMETHOD(device_attach, ufoma_attach), 301 DEVMETHOD(device_detach, ufoma_detach), 302 {0, 0} 303 }; 304 305 static devclass_t ufoma_devclass; 306 307 static driver_t ufoma_driver = { 308 .name = "ufoma", 309 .methods = ufoma_methods, 310 .size = sizeof(struct ufoma_softc), 311 }; 312 313 DRIVER_MODULE(ufoma, uhub, ufoma_driver, ufoma_devclass, NULL, 0); 314 MODULE_DEPEND(ufoma, ucom, 1, 1, 1); 315 MODULE_DEPEND(ufoma, usb, 1, 1, 1); 316 317 static int 318 ufoma_probe(device_t dev) 319 { 320 struct usb2_attach_arg *uaa = device_get_ivars(dev); 321 struct usb2_interface_descriptor *id; 322 struct usb2_config_descriptor *cd; 323 usb2_mcpc_acm_descriptor *mad; 324 325 if (uaa->usb2_mode != USB_MODE_HOST) { 326 return (ENXIO); 327 } 328 id = usb2_get_interface_descriptor(uaa->iface); 329 cd = usb2_get_config_descriptor(uaa->device); 330 331 if ((id == NULL) || 332 (cd == NULL) || 333 (id->bInterfaceClass != UICLASS_CDC) || 334 (id->bInterfaceSubClass != UISUBCLASS_MCPC)) { 335 return (ENXIO); 336 } 337 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM); 338 if (mad == NULL) { 339 return (ENXIO); 340 } 341 #ifndef UFOMA_HANDSFREE 342 if ((mad->bType == UMCPC_ACM_TYPE_AB5) || 343 (mad->bType == UMCPC_ACM_TYPE_AB6)) { 344 return (ENXIO); 345 } 346 #endif 347 return (0); 348 } 349 350 static int 351 ufoma_attach(device_t dev) 352 { 353 struct usb2_attach_arg *uaa = device_get_ivars(dev); 354 struct ufoma_softc *sc = device_get_softc(dev); 355 struct usb2_config_descriptor *cd; 356 struct usb2_interface_descriptor *id; 357 struct sysctl_ctx_list *sctx; 358 struct sysctl_oid *soid; 359 360 usb2_mcpc_acm_descriptor *mad; 361 uint8_t elements; 362 int32_t error; 363 364 sc->sc_udev = uaa->device; 365 sc->sc_dev = dev; 366 sc->sc_unit = device_get_unit(dev); 367 368 mtx_init(&sc->sc_mtx, "ufoma", NULL, MTX_DEF); 369 usb2_cv_init(&sc->sc_cv, "CWAIT"); 370 371 device_set_usb2_desc(dev); 372 373 snprintf(sc->sc_name, sizeof(sc->sc_name), 374 "%s", device_get_nameunit(dev)); 375 376 DPRINTF("\n"); 377 378 /* setup control transfers */ 379 380 cd = usb2_get_config_descriptor(uaa->device); 381 id = usb2_get_interface_descriptor(uaa->iface); 382 sc->sc_ctrl_iface_no = id->bInterfaceNumber; 383 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex; 384 385 error = usb2_transfer_setup(uaa->device, 386 &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer, 387 ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &sc->sc_mtx); 388 389 if (error) { 390 device_printf(dev, "allocating control USB " 391 "transfers failed!\n"); 392 goto detach; 393 } 394 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM); 395 if (mad == NULL) { 396 goto detach; 397 } 398 if (mad->bFunctionLength < sizeof(*mad)) { 399 device_printf(dev, "invalid MAD descriptor\n"); 400 goto detach; 401 } 402 if ((mad->bType == UMCPC_ACM_TYPE_AB5) || 403 (mad->bType == UMCPC_ACM_TYPE_AB6)) { 404 sc->sc_nobulk = 1; 405 } else { 406 sc->sc_nobulk = 0; 407 if (ufoma_modem_setup(dev, sc, uaa)) { 408 goto detach; 409 } 410 } 411 412 elements = (mad->bFunctionLength - sizeof(*mad) + 1); 413 414 /* initialize mode variables */ 415 416 sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK); 417 418 if (sc->sc_modetable == NULL) { 419 goto detach; 420 } 421 sc->sc_modetable[0] = (elements + 1); 422 bcopy(mad->bMode, &sc->sc_modetable[1], elements); 423 424 sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED; 425 sc->sc_modetoactivate = mad->bMode[0]; 426 427 /* clear stall at first run, if any */ 428 mtx_lock(&sc->sc_mtx); 429 usb2_transfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); 430 usb2_transfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); 431 mtx_unlock(&sc->sc_mtx); 432 433 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 434 &ufoma_callback, &sc->sc_mtx); 435 if (error) { 436 DPRINTF("usb2_com_attach failed\n"); 437 goto detach; 438 } 439 /*Sysctls*/ 440 sctx = device_get_sysctl_ctx(dev); 441 soid = device_get_sysctl_tree(dev); 442 443 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode", 444 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support, 445 "A", "Supporting port role"); 446 447 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode", 448 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current, 449 "A", "Current port role"); 450 451 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode", 452 CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open, 453 "A", "Mode to transit when port is opened"); 454 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit", 455 CTLFLAG_RD, &(sc->sc_ucom.sc_unit), 0, 456 "Unit number as USB serial"); 457 458 return (0); /* success */ 459 460 detach: 461 ufoma_detach(dev); 462 return (ENXIO); /* failure */ 463 } 464 465 static int 466 ufoma_detach(device_t dev) 467 { 468 struct ufoma_softc *sc = device_get_softc(dev); 469 470 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 471 usb2_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX); 472 usb2_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX); 473 474 if (sc->sc_modetable) { 475 free(sc->sc_modetable, M_USBDEV); 476 } 477 mtx_destroy(&sc->sc_mtx); 478 usb2_cv_destroy(&sc->sc_cv); 479 480 return (0); 481 } 482 483 static void * 484 ufoma_get_intconf(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id, 485 uint8_t type, uint8_t subtype) 486 { 487 struct usb2_descriptor *desc = (void *)id; 488 489 while ((desc = usb2_desc_foreach(cd, desc))) { 490 491 if (desc->bDescriptorType == UDESC_INTERFACE) { 492 return (NULL); 493 } 494 if ((desc->bDescriptorType == type) && 495 (desc->bDescriptorSubtype == subtype)) { 496 break; 497 } 498 } 499 return (desc); 500 } 501 502 static void 503 ufoma_cfg_link_state(struct ufoma_softc *sc) 504 { 505 struct usb2_device_request req; 506 int32_t error; 507 508 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; 509 req.bRequest = UMCPC_SET_LINK; 510 USETW(req.wValue, UMCPC_CM_MOBILE_ACM); 511 USETW(req.wIndex, sc->sc_ctrl_iface_no); 512 USETW(req.wLength, sc->sc_modetable[0]); 513 514 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 515 &req, sc->sc_modetable, 0, 1000); 516 517 error = usb2_cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz); 518 519 if (error) { 520 DPRINTF("NO response\n"); 521 } 522 } 523 524 static void 525 ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state) 526 { 527 struct usb2_device_request req; 528 int32_t error; 529 530 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; 531 req.bRequest = UMCPC_ACTIVATE_MODE; 532 USETW(req.wValue, state); 533 USETW(req.wIndex, sc->sc_ctrl_iface_no); 534 USETW(req.wLength, 0); 535 536 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 537 &req, NULL, 0, 1000); 538 539 error = usb2_cv_timedwait(&sc->sc_cv, &sc->sc_mtx, 540 (UFOMA_MAX_TIMEOUT * hz)); 541 if (error) { 542 DPRINTF("No response\n"); 543 } 544 } 545 546 static void 547 ufoma_ctrl_read_callback(struct usb2_xfer *xfer) 548 { 549 struct ufoma_softc *sc = xfer->priv_sc; 550 struct usb2_device_request req; 551 552 switch (USB_GET_STATE(xfer)) { 553 case USB_ST_TRANSFERRED: 554 tr_transferred: 555 if (xfer->aframes != xfer->nframes) { 556 goto tr_setup; 557 } 558 if (xfer->frlengths[1] > 0) { 559 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers + 1, 560 0, xfer->frlengths[1]); 561 } 562 case USB_ST_SETUP: 563 tr_setup: 564 if (sc->sc_num_msg) { 565 sc->sc_num_msg--; 566 567 req.bmRequestType = UT_READ_CLASS_INTERFACE; 568 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; 569 USETW(req.wIndex, sc->sc_ctrl_iface_no); 570 USETW(req.wValue, 0); 571 USETW(req.wLength, UFOMA_CMD_BUF_SIZE); 572 573 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 574 575 xfer->frlengths[0] = sizeof(req); 576 xfer->frlengths[1] = UFOMA_CMD_BUF_SIZE; 577 xfer->nframes = 2; 578 usb2_start_hardware(xfer); 579 } 580 return; 581 582 default: /* Error */ 583 DPRINTF("error = %s\n", 584 usb2_errstr(xfer->error)); 585 586 if (xfer->error == USB_ERR_CANCELLED) { 587 return; 588 } else { 589 goto tr_setup; 590 } 591 592 goto tr_transferred; 593 } 594 } 595 596 static void 597 ufoma_ctrl_write_callback(struct usb2_xfer *xfer) 598 { 599 struct ufoma_softc *sc = xfer->priv_sc; 600 struct usb2_device_request req; 601 uint32_t actlen; 602 603 switch (USB_GET_STATE(xfer)) { 604 case USB_ST_TRANSFERRED: 605 tr_transferred: 606 case USB_ST_SETUP: 607 tr_setup: 608 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1, 609 0, 1, &actlen)) { 610 611 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 612 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND; 613 USETW(req.wIndex, sc->sc_ctrl_iface_no); 614 USETW(req.wValue, 0); 615 USETW(req.wLength, 1); 616 617 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 618 619 xfer->frlengths[0] = sizeof(req); 620 xfer->frlengths[1] = 1; 621 xfer->nframes = 2; 622 623 usb2_start_hardware(xfer); 624 } 625 return; 626 627 default: /* Error */ 628 DPRINTF("error = %s\n", 629 usb2_errstr(xfer->error)); 630 631 if (xfer->error == USB_ERR_CANCELLED) { 632 return; 633 } else { 634 goto tr_setup; 635 } 636 637 goto tr_transferred; 638 } 639 } 640 641 static void 642 ufoma_intr_callback(struct usb2_xfer *xfer) 643 { 644 struct ufoma_softc *sc = xfer->priv_sc; 645 struct usb2_cdc_notification pkt; 646 uint16_t wLen; 647 uint16_t temp; 648 uint8_t mstatus; 649 650 switch (USB_GET_STATE(xfer)) { 651 case USB_ST_TRANSFERRED: 652 if (xfer->actlen < 8) { 653 DPRINTF("too short message\n"); 654 goto tr_setup; 655 } 656 if (xfer->actlen > sizeof(pkt)) { 657 DPRINTF("truncating message\n"); 658 xfer->actlen = sizeof(pkt); 659 } 660 usb2_copy_out(xfer->frbuffers, 0, &pkt, xfer->actlen); 661 662 xfer->actlen -= 8; 663 664 wLen = UGETW(pkt.wLength); 665 if (xfer->actlen > wLen) { 666 xfer->actlen = wLen; 667 } 668 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) && 669 (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) { 670 temp = UGETW(pkt.wValue); 671 sc->sc_currentmode = (temp >> 8); 672 if (!(temp & 0xff)) { 673 DPRINTF("Mode change failed!\n"); 674 } 675 usb2_cv_signal(&sc->sc_cv); 676 } 677 if (pkt.bmRequestType != UCDC_NOTIFICATION) { 678 goto tr_setup; 679 } 680 switch (pkt.bNotification) { 681 case UCDC_N_RESPONSE_AVAILABLE: 682 if (!(sc->sc_nobulk)) { 683 DPRINTF("Wrong serial state!\n"); 684 break; 685 } 686 if (sc->sc_num_msg != 0xFF) { 687 sc->sc_num_msg++; 688 } 689 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); 690 break; 691 692 case UCDC_N_SERIAL_STATE: 693 if (sc->sc_nobulk) { 694 DPRINTF("Wrong serial state!\n"); 695 break; 696 } 697 /* 698 * Set the serial state in ucom driver based on 699 * the bits from the notify message 700 */ 701 if (xfer->actlen < 2) { 702 DPRINTF("invalid notification " 703 "length, %d bytes!\n", xfer->actlen); 704 break; 705 } 706 DPRINTF("notify bytes = 0x%02x, 0x%02x\n", 707 pkt.data[0], pkt.data[1]); 708 709 /* currently, lsr is always zero. */ 710 sc->sc_lsr = 0; 711 sc->sc_msr = 0; 712 713 mstatus = pkt.data[0]; 714 715 if (mstatus & UCDC_N_SERIAL_RI) { 716 sc->sc_msr |= SER_RI; 717 } 718 if (mstatus & UCDC_N_SERIAL_DSR) { 719 sc->sc_msr |= SER_DSR; 720 } 721 if (mstatus & UCDC_N_SERIAL_DCD) { 722 sc->sc_msr |= SER_DCD; 723 } 724 usb2_com_status_change(&sc->sc_ucom); 725 break; 726 727 default: 728 break; 729 } 730 731 case USB_ST_SETUP: 732 tr_setup: 733 xfer->frlengths[0] = xfer->max_data_length; 734 usb2_start_hardware(xfer); 735 return; 736 737 default: /* Error */ 738 if (xfer->error != USB_ERR_CANCELLED) { 739 /* try to clear stall first */ 740 xfer->flags.stall_pipe = 1; 741 goto tr_setup; 742 } 743 return; 744 } 745 } 746 747 static void 748 ufoma_bulk_write_callback(struct usb2_xfer *xfer) 749 { 750 struct ufoma_softc *sc = xfer->priv_sc; 751 uint32_t actlen; 752 753 switch (USB_GET_STATE(xfer)) { 754 case USB_ST_SETUP: 755 case USB_ST_TRANSFERRED: 756 tr_setup: 757 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 758 UFOMA_BULK_BUF_SIZE, &actlen)) { 759 xfer->frlengths[0] = actlen; 760 usb2_start_hardware(xfer); 761 } 762 return; 763 764 default: /* Error */ 765 if (xfer->error != USB_ERR_CANCELLED) { 766 /* try to clear stall first */ 767 xfer->flags.stall_pipe = 1; 768 goto tr_setup; 769 } 770 return; 771 } 772 } 773 774 static void 775 ufoma_bulk_read_callback(struct usb2_xfer *xfer) 776 { 777 struct ufoma_softc *sc = xfer->priv_sc; 778 779 switch (USB_GET_STATE(xfer)) { 780 case USB_ST_TRANSFERRED: 781 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, 782 xfer->actlen); 783 784 case USB_ST_SETUP: 785 tr_setup: 786 xfer->frlengths[0] = xfer->max_data_length; 787 usb2_start_hardware(xfer); 788 return; 789 790 default: /* Error */ 791 if (xfer->error != USB_ERR_CANCELLED) { 792 /* try to clear stall first */ 793 xfer->flags.stall_pipe = 1; 794 goto tr_setup; 795 } 796 return; 797 } 798 } 799 800 static void 801 ufoma_cfg_open(struct usb2_com_softc *ucom) 802 { 803 struct ufoma_softc *sc = ucom->sc_parent; 804 805 /* empty input queue */ 806 807 if (sc->sc_num_msg != 0xFF) { 808 sc->sc_num_msg++; 809 } 810 if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) { 811 ufoma_cfg_link_state(sc); 812 } 813 if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) { 814 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate); 815 } 816 } 817 818 static void 819 ufoma_cfg_close(struct usb2_com_softc *ucom) 820 { 821 struct ufoma_softc *sc = ucom->sc_parent; 822 823 ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED); 824 } 825 826 static void 827 ufoma_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 828 { 829 struct ufoma_softc *sc = ucom->sc_parent; 830 struct usb2_device_request req; 831 uint16_t wValue; 832 833 if (sc->sc_nobulk || 834 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) { 835 return; 836 } 837 if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) { 838 return; 839 } 840 wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF; 841 842 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 843 req.bRequest = UCDC_SEND_BREAK; 844 USETW(req.wValue, wValue); 845 req.wIndex[0] = sc->sc_ctrl_iface_no; 846 req.wIndex[1] = 0; 847 USETW(req.wLength, 0); 848 849 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 850 &req, NULL, 0, 1000); 851 } 852 853 static void 854 ufoma_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 855 { 856 struct ufoma_softc *sc = ucom->sc_parent; 857 858 *lsr = sc->sc_lsr; 859 *msr = sc->sc_msr; 860 } 861 862 static void 863 ufoma_cfg_set_line_state(struct ufoma_softc *sc) 864 { 865 struct usb2_device_request req; 866 867 /* Don't send line state emulation request for OBEX port */ 868 if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) { 869 return; 870 } 871 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 872 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 873 USETW(req.wValue, sc->sc_line); 874 req.wIndex[0] = sc->sc_ctrl_iface_no; 875 req.wIndex[1] = 0; 876 USETW(req.wLength, 0); 877 878 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 879 &req, NULL, 0, 1000); 880 } 881 882 static void 883 ufoma_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 884 { 885 struct ufoma_softc *sc = ucom->sc_parent; 886 887 if (sc->sc_nobulk) { 888 return; 889 } 890 if (onoff) 891 sc->sc_line |= UCDC_LINE_DTR; 892 else 893 sc->sc_line &= ~UCDC_LINE_DTR; 894 895 ufoma_cfg_set_line_state(sc); 896 } 897 898 static void 899 ufoma_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 900 { 901 struct ufoma_softc *sc = ucom->sc_parent; 902 903 if (sc->sc_nobulk) { 904 return; 905 } 906 if (onoff) 907 sc->sc_line |= UCDC_LINE_RTS; 908 else 909 sc->sc_line &= ~UCDC_LINE_RTS; 910 911 ufoma_cfg_set_line_state(sc); 912 } 913 914 static int 915 ufoma_pre_param(struct usb2_com_softc *ucom, struct termios *t) 916 { 917 return (0); /* we accept anything */ 918 } 919 920 static void 921 ufoma_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 922 { 923 struct ufoma_softc *sc = ucom->sc_parent; 924 struct usb2_device_request req; 925 struct usb2_cdc_line_state ls; 926 927 if (sc->sc_nobulk || 928 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) { 929 return; 930 } 931 DPRINTF("\n"); 932 933 bzero(&ls, sizeof(ls)); 934 935 USETDW(ls.dwDTERate, t->c_ospeed); 936 937 if (t->c_cflag & CSTOPB) { 938 ls.bCharFormat = UCDC_STOP_BIT_2; 939 } else { 940 ls.bCharFormat = UCDC_STOP_BIT_1; 941 } 942 943 if (t->c_cflag & PARENB) { 944 if (t->c_cflag & PARODD) { 945 ls.bParityType = UCDC_PARITY_ODD; 946 } else { 947 ls.bParityType = UCDC_PARITY_EVEN; 948 } 949 } else { 950 ls.bParityType = UCDC_PARITY_NONE; 951 } 952 953 switch (t->c_cflag & CSIZE) { 954 case CS5: 955 ls.bDataBits = 5; 956 break; 957 case CS6: 958 ls.bDataBits = 6; 959 break; 960 case CS7: 961 ls.bDataBits = 7; 962 break; 963 case CS8: 964 ls.bDataBits = 8; 965 break; 966 } 967 968 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 969 req.bRequest = UCDC_SET_LINE_CODING; 970 USETW(req.wValue, 0); 971 req.wIndex[0] = sc->sc_ctrl_iface_no; 972 req.wIndex[1] = 0; 973 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 974 975 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 976 &req, &ls, 0, 1000); 977 } 978 979 static int 980 ufoma_modem_setup(device_t dev, struct ufoma_softc *sc, 981 struct usb2_attach_arg *uaa) 982 { 983 struct usb2_config_descriptor *cd; 984 struct usb2_cdc_acm_descriptor *acm; 985 struct usb2_cdc_cm_descriptor *cmd; 986 struct usb2_interface_descriptor *id; 987 struct usb2_interface *iface; 988 uint8_t i; 989 int32_t error; 990 991 cd = usb2_get_config_descriptor(uaa->device); 992 id = usb2_get_interface_descriptor(uaa->iface); 993 994 cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 995 996 if ((cmd == NULL) || 997 (cmd->bLength < sizeof(*cmd))) { 998 return (EINVAL); 999 } 1000 sc->sc_cm_cap = cmd->bmCapabilities; 1001 sc->sc_data_iface_no = cmd->bDataInterface; 1002 1003 acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); 1004 1005 if ((acm == NULL) || 1006 (acm->bLength < sizeof(*acm))) { 1007 return (EINVAL); 1008 } 1009 sc->sc_acm_cap = acm->bmCapabilities; 1010 1011 device_printf(dev, "data interface %d, has %sCM over data, " 1012 "has %sbreak\n", 1013 sc->sc_data_iface_no, 1014 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", 1015 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); 1016 1017 /* get the data interface too */ 1018 1019 for (i = 0;; i++) { 1020 1021 iface = usb2_get_iface(uaa->device, i); 1022 1023 if (iface) { 1024 1025 id = usb2_get_interface_descriptor(iface); 1026 1027 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) { 1028 sc->sc_data_iface_index = i; 1029 usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 1030 break; 1031 } 1032 } else { 1033 device_printf(dev, "no data interface!\n"); 1034 return (EINVAL); 1035 } 1036 } 1037 1038 error = usb2_transfer_setup(uaa->device, 1039 &sc->sc_data_iface_index, sc->sc_bulk_xfer, 1040 ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &sc->sc_mtx); 1041 1042 if (error) { 1043 device_printf(dev, "allocating BULK USB " 1044 "transfers failed!\n"); 1045 return (EINVAL); 1046 } 1047 return (0); 1048 } 1049 1050 static void 1051 ufoma_start_read(struct usb2_com_softc *ucom) 1052 { 1053 struct ufoma_softc *sc = ucom->sc_parent; 1054 1055 /* start interrupt transfer */ 1056 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]); 1057 1058 /* start data transfer */ 1059 if (sc->sc_nobulk) { 1060 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); 1061 } else { 1062 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); 1063 } 1064 } 1065 1066 static void 1067 ufoma_stop_read(struct usb2_com_softc *ucom) 1068 { 1069 struct ufoma_softc *sc = ucom->sc_parent; 1070 1071 /* stop interrupt transfer */ 1072 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]); 1073 1074 /* stop data transfer */ 1075 if (sc->sc_nobulk) { 1076 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); 1077 } else { 1078 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); 1079 } 1080 } 1081 1082 static void 1083 ufoma_start_write(struct usb2_com_softc *ucom) 1084 { 1085 struct ufoma_softc *sc = ucom->sc_parent; 1086 1087 if (sc->sc_nobulk) { 1088 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]); 1089 } else { 1090 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); 1091 } 1092 } 1093 1094 static void 1095 ufoma_stop_write(struct usb2_com_softc *ucom) 1096 { 1097 struct ufoma_softc *sc = ucom->sc_parent; 1098 1099 if (sc->sc_nobulk) { 1100 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]); 1101 } else { 1102 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); 1103 } 1104 } 1105 1106 struct umcpc_modetostr_tab{ 1107 int mode; 1108 char *str; 1109 }umcpc_modetostr_tab[]={ 1110 {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"}, 1111 {UMCPC_ACM_MODE_MODEM, "modem"}, 1112 {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"}, 1113 {UMCPC_ACM_MODE_OBEX, "obex"}, 1114 {UMCPC_ACM_MODE_VENDOR1, "vendor1"}, 1115 {UMCPC_ACM_MODE_VENDOR2, "vendor2"}, 1116 {UMCPC_ACM_MODE_UNLINKED, "unlinked"}, 1117 {0, NULL} 1118 }; 1119 1120 static char *ufoma_mode_to_str(int mode) 1121 { 1122 int i; 1123 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){ 1124 if(umcpc_modetostr_tab[i].mode == mode){ 1125 return umcpc_modetostr_tab[i].str; 1126 } 1127 } 1128 return NULL; 1129 } 1130 1131 static int ufoma_str_to_mode(char *str) 1132 { 1133 int i; 1134 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){ 1135 if(strcmp(str, umcpc_modetostr_tab[i].str)==0){ 1136 return umcpc_modetostr_tab[i].mode; 1137 } 1138 } 1139 return -1; 1140 } 1141 1142 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS) 1143 { 1144 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; 1145 struct sbuf sb; 1146 int i; 1147 char *mode; 1148 1149 sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND); 1150 for(i = 1; i < sc->sc_modetable[0]; i++){ 1151 mode = ufoma_mode_to_str(sc->sc_modetable[i]); 1152 if(mode !=NULL){ 1153 sbuf_cat(&sb, mode); 1154 }else{ 1155 sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]); 1156 } 1157 if(i < (sc->sc_modetable[0]-1)) 1158 sbuf_cat(&sb, ","); 1159 } 1160 sbuf_trim(&sb); 1161 sbuf_finish(&sb); 1162 sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 1163 sbuf_delete(&sb); 1164 1165 return 0; 1166 } 1167 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS) 1168 { 1169 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; 1170 char *mode; 1171 char subbuf[]="(XXX)"; 1172 mode = ufoma_mode_to_str(sc->sc_currentmode); 1173 if(!mode){ 1174 mode = subbuf; 1175 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode); 1176 } 1177 sysctl_handle_string(oidp, mode, strlen(mode), req); 1178 1179 return 0; 1180 1181 } 1182 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS) 1183 { 1184 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; 1185 char *mode; 1186 char subbuf[40]; 1187 int newmode; 1188 int error; 1189 int i; 1190 1191 mode = ufoma_mode_to_str(sc->sc_modetoactivate); 1192 if(mode){ 1193 strncpy(subbuf, mode, sizeof(subbuf)); 1194 }else{ 1195 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate); 1196 } 1197 error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req); 1198 if(error != 0 || req->newptr == NULL){ 1199 return error; 1200 } 1201 1202 if((newmode = ufoma_str_to_mode(subbuf)) == -1){ 1203 return EINVAL; 1204 } 1205 1206 for(i = 1 ; i < sc->sc_modetable[0] ; i++){ 1207 if(sc->sc_modetable[i] == newmode){ 1208 sc->sc_modetoactivate = newmode; 1209 return 0; 1210 } 1211 } 1212 1213 return EINVAL; 1214 } 1215