96#include <dev/usb2/core/usb2_request.h> 97#include <dev/usb2/core/usb2_lookup.h> 98#include <dev/usb2/core/usb2_util.h> 99#include <dev/usb2/core/usb2_busdma.h> 100#include <dev/usb2/core/usb2_device.h> 101 102#include <dev/usb2/serial/usb2_serial.h> 103 104#if USB_DEBUG 105static int umodem_debug = 0; 106 107SYSCTL_NODE(_hw_usb2, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); 108SYSCTL_INT(_hw_usb2_umodem, OID_AUTO, debug, CTLFLAG_RW, 109 &umodem_debug, 0, "Debug level"); 110#endif 111 112static const struct usb2_device_id umodem_devs[] = { 113 /* Generic Modem class match */ 114 {USB_IFACE_CLASS(UICLASS_CDC), 115 USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), 116 USB_IFACE_PROTOCOL(UIPROTO_CDC_AT)}, 117 /* Kyocera AH-K3001V */ 118 {USB_VPI(USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_AHK3001V, 1)}, 119 {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, 1)}, 120 {USB_VPI(USB_VENDOR_CURITEL, USB_PRODUCT_CURITEL_PC5740, 1)}, 121}; 122 123/* 124 * As speeds for umodem deivces increase, these numbers will need to 125 * be increased. They should be good for G3 speeds and below. 126 * 127 * TODO: The TTY buffers should be increased! 128 */ 129#define UMODEM_BUF_SIZE 1024 130#define UMODEM_N_DATA_TRANSFER 4 131#define UMODEM_N_INTR_TRANSFER 2 132 133#define UMODEM_MODVER 1 /* module version */ 134 135struct umodem_softc { 136 struct usb2_com_super_softc sc_super_ucom; 137 struct usb2_com_softc sc_ucom; 138 139 struct usb2_xfer *sc_xfer_data[UMODEM_N_DATA_TRANSFER]; 140 struct usb2_xfer *sc_xfer_intr[UMODEM_N_INTR_TRANSFER]; 141 struct usb2_device *sc_udev; 142 143 uint16_t sc_line; 144 145 uint8_t sc_lsr; /* local status register */ 146 uint8_t sc_msr; /* modem status register */ 147 uint8_t sc_ctrl_iface_no; 148 uint8_t sc_ctrl_iface_index; 149 uint8_t sc_data_iface_no; 150 uint8_t sc_data_iface_index; 151 uint8_t sc_cm_over_data; 152 uint8_t sc_cm_cap; /* CM capabilities */ 153 uint8_t sc_acm_cap; /* ACM capabilities */ 154 uint8_t sc_flag; 155#define UMODEM_FLAG_READ_STALL 0x01 156#define UMODEM_FLAG_WRITE_STALL 0x02 157#define UMODEM_FLAG_INTR_STALL 0x04 158}; 159 160static device_probe_t umodem_probe; 161static device_attach_t umodem_attach; 162static device_detach_t umodem_detach; 163 164static usb2_callback_t umodem_intr_callback; 165static usb2_callback_t umodem_intr_clear_stall_callback; 166static usb2_callback_t umodem_write_callback; 167static usb2_callback_t umodem_read_callback; 168static usb2_callback_t umodem_write_clear_stall_callback; 169static usb2_callback_t umodem_read_clear_stall_callback; 170 171static void umodem_start_read(struct usb2_com_softc *); 172static void umodem_stop_read(struct usb2_com_softc *); 173static void umodem_start_write(struct usb2_com_softc *); 174static void umodem_stop_write(struct usb2_com_softc *); 175static void umodem_get_caps(struct usb2_attach_arg *, uint8_t *, uint8_t *); 176static void umodem_cfg_get_status(struct usb2_com_softc *, uint8_t *, 177 uint8_t *); 178static int umodem_pre_param(struct usb2_com_softc *, struct termios *); 179static void umodem_cfg_param(struct usb2_com_softc *, struct termios *); 180static int umodem_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int, 181 struct thread *); 182static void umodem_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 183static void umodem_cfg_set_rts(struct usb2_com_softc *, uint8_t); 184static void umodem_cfg_set_break(struct usb2_com_softc *, uint8_t); 185static void *umodem_get_desc(struct usb2_attach_arg *, uint8_t, uint8_t); 186static usb2_error_t umodem_set_comm_feature(struct usb2_device *, uint8_t, 187 uint16_t, uint16_t); 188static void umodem_cfg_do_request(struct umodem_softc *, 189 struct usb2_device_request *, void *); 190 191static const struct usb2_config umodem_config_data[UMODEM_N_DATA_TRANSFER] = { 192 193 [0] = { 194 .type = UE_BULK, 195 .endpoint = UE_ADDR_ANY, 196 .direction = UE_DIR_OUT, 197 .mh.bufsize = UMODEM_BUF_SIZE, 198 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 199 .mh.callback = &umodem_write_callback, 200 }, 201 202 [1] = { 203 .type = UE_BULK, 204 .endpoint = UE_ADDR_ANY, 205 .direction = UE_DIR_IN, 206 .mh.bufsize = UMODEM_BUF_SIZE, 207 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 208 .mh.callback = &umodem_read_callback, 209 }, 210 211 [2] = { 212 .type = UE_CONTROL, 213 .endpoint = 0x00, /* Control pipe */ 214 .direction = UE_DIR_ANY, 215 .mh.bufsize = sizeof(struct usb2_device_request), 216 .mh.callback = &umodem_write_clear_stall_callback, 217 .mh.timeout = 1000, /* 1 second */ 218 .mh.interval = 50, /* 50ms */ 219 }, 220 221 [3] = { 222 .type = UE_CONTROL, 223 .endpoint = 0x00, /* Control pipe */ 224 .direction = UE_DIR_ANY, 225 .mh.bufsize = sizeof(struct usb2_device_request), 226 .mh.callback = &umodem_read_clear_stall_callback, 227 .mh.timeout = 1000, /* 1 second */ 228 .mh.interval = 50, /* 50ms */ 229 }, 230}; 231 232static const struct usb2_config umodem_config_intr[UMODEM_N_INTR_TRANSFER] = { 233 [0] = { 234 .type = UE_INTERRUPT, 235 .endpoint = UE_ADDR_ANY, 236 .direction = UE_DIR_IN, 237 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 238 .mh.bufsize = 0, /* use wMaxPacketSize */ 239 .mh.callback = &umodem_intr_callback, 240 }, 241 242 [1] = { 243 .type = UE_CONTROL, 244 .endpoint = 0x00, /* Control pipe */ 245 .direction = UE_DIR_ANY, 246 .mh.bufsize = sizeof(struct usb2_device_request), 247 .mh.callback = &umodem_intr_clear_stall_callback, 248 .mh.timeout = 1000, /* 1 second */ 249 .mh.interval = 50, /* 50ms */ 250 }, 251}; 252 253static const struct usb2_com_callback umodem_callback = { 254 .usb2_com_cfg_get_status = &umodem_cfg_get_status, 255 .usb2_com_cfg_set_dtr = &umodem_cfg_set_dtr, 256 .usb2_com_cfg_set_rts = &umodem_cfg_set_rts, 257 .usb2_com_cfg_set_break = &umodem_cfg_set_break, 258 .usb2_com_cfg_param = &umodem_cfg_param, 259 .usb2_com_pre_param = &umodem_pre_param, 260 .usb2_com_ioctl = &umodem_ioctl, 261 .usb2_com_start_read = &umodem_start_read, 262 .usb2_com_stop_read = &umodem_stop_read, 263 .usb2_com_start_write = &umodem_start_write, 264 .usb2_com_stop_write = &umodem_stop_write, 265}; 266 267static device_method_t umodem_methods[] = { 268 DEVMETHOD(device_probe, umodem_probe), 269 DEVMETHOD(device_attach, umodem_attach), 270 DEVMETHOD(device_detach, umodem_detach), 271 {0, 0} 272}; 273 274static devclass_t umodem_devclass; 275 276static driver_t umodem_driver = { 277 .name = "umodem", 278 .methods = umodem_methods, 279 .size = sizeof(struct umodem_softc), 280}; 281 282DRIVER_MODULE(umodem, ushub, umodem_driver, umodem_devclass, NULL, 0); 283MODULE_DEPEND(umodem, usb2_serial, 1, 1, 1); 284MODULE_DEPEND(umodem, usb2_core, 1, 1, 1); 285MODULE_VERSION(umodem, UMODEM_MODVER); 286 287static int 288umodem_probe(device_t dev) 289{ 290 struct usb2_attach_arg *uaa = device_get_ivars(dev); 291 uint8_t cm; 292 uint8_t acm; 293 int error; 294 295 DPRINTFN(11, "\n"); 296 297 if (uaa->usb2_mode != USB_MODE_HOST) { 298 return (ENXIO); 299 } 300 error = usb2_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa); 301 if (error) { 302 return (error); 303 } 304 if (uaa->driver_info == NULL) { 305 /* some modems do not have any capabilities */ 306 return (error); 307 } 308 umodem_get_caps(uaa, &cm, &acm); 309 if (!(cm & USB_CDC_CM_DOES_CM) || 310 !(cm & USB_CDC_CM_OVER_DATA) || 311 !(acm & USB_CDC_ACM_HAS_LINE)) { 312 error = ENXIO; 313 } 314 return (error); 315} 316 317static int 318umodem_attach(device_t dev) 319{ 320 struct usb2_attach_arg *uaa = device_get_ivars(dev); 321 struct umodem_softc *sc = device_get_softc(dev); 322 struct usb2_cdc_cm_descriptor *cmd; 323 uint8_t i; 324 int error; 325 326 if (sc == NULL) { 327 return (ENOMEM); 328 } 329 device_set_usb2_desc(dev); 330 331 sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; 332 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex; 333 sc->sc_udev = uaa->device; 334 335 umodem_get_caps(uaa, &sc->sc_cm_cap, &sc->sc_acm_cap); 336 337 /* get the data interface number */ 338 339 cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 340 341 if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { 342 device_printf(dev, "no CM descriptor!\n"); 343 goto detach; 344 } 345 sc->sc_data_iface_no = cmd->bDataInterface; 346 347 device_printf(dev, "data interface %d, has %sCM over " 348 "data, has %sbreak\n", 349 sc->sc_data_iface_no, 350 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", 351 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); 352 353 /* get the data interface too */ 354 355 for (i = 0;; i++) { 356 struct usb2_interface *iface; 357 struct usb2_interface_descriptor *id; 358 359 iface = usb2_get_iface(uaa->device, i); 360 361 if (iface) { 362 363 id = usb2_get_interface_descriptor(iface); 364 365 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) { 366 sc->sc_data_iface_index = i; 367 usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 368 break; 369 } 370 } else { 371 device_printf(dev, "no data interface!\n"); 372 goto detach; 373 } 374 } 375 376 if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { 377 if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) { 378 379 error = umodem_set_comm_feature 380 (uaa->device, sc->sc_ctrl_iface_no, 381 UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); 382 383 /* ignore any errors */ 384 } 385 sc->sc_cm_over_data = 1; 386 } 387 error = usb2_transfer_setup(uaa->device, 388 &sc->sc_data_iface_index, sc->sc_xfer_data, 389 umodem_config_data, UMODEM_N_DATA_TRANSFER, 390 sc, &Giant); 391 if (error) { 392 goto detach; 393 } 394 error = usb2_transfer_setup(uaa->device, 395 &sc->sc_ctrl_iface_index, sc->sc_xfer_intr, 396 umodem_config_intr, UMODEM_N_INTR_TRANSFER, 397 sc, &Giant); 398 399 if (error == 0) { 400 device_printf(dev, "status change " 401 "notification available\n"); 402 } 403 /* clear stall at first run */ 404 sc->sc_flag |= (UMODEM_FLAG_READ_STALL | 405 UMODEM_FLAG_WRITE_STALL); 406 407 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 408 &umodem_callback, &Giant); 409 if (error) { 410 goto detach; 411 } 412 return (0); 413 414detach: 415 umodem_detach(dev); 416 return (ENXIO); 417} 418 419static void 420umodem_start_read(struct usb2_com_softc *ucom) 421{ 422 struct umodem_softc *sc = ucom->sc_parent; 423 424 if (sc->sc_xfer_intr[0]) { 425 /* start interrupt endpoint */ 426 usb2_transfer_start(sc->sc_xfer_intr[0]); 427 } 428 /* start read endpoint */ 429 usb2_transfer_start(sc->sc_xfer_data[1]); 430} 431 432static void 433umodem_stop_read(struct usb2_com_softc *ucom) 434{ 435 struct umodem_softc *sc = ucom->sc_parent; 436 437 if (sc->sc_xfer_intr[0]) { 438 /* stop interrupt endpoint */ 439 usb2_transfer_stop(sc->sc_xfer_intr[0]); 440 } 441 /* stop read endpoint */ 442 usb2_transfer_stop(sc->sc_xfer_data[3]); 443 usb2_transfer_stop(sc->sc_xfer_data[1]); 444} 445 446static void 447umodem_start_write(struct usb2_com_softc *ucom) 448{ 449 struct umodem_softc *sc = ucom->sc_parent; 450 451 usb2_transfer_start(sc->sc_xfer_data[0]); 452} 453 454static void 455umodem_stop_write(struct usb2_com_softc *ucom) 456{ 457 struct umodem_softc *sc = ucom->sc_parent; 458 459 usb2_transfer_stop(sc->sc_xfer_data[2]); 460 usb2_transfer_stop(sc->sc_xfer_data[0]); 461} 462 463static void 464umodem_get_caps(struct usb2_attach_arg *uaa, uint8_t *cm, uint8_t *acm) 465{ 466 struct usb2_cdc_cm_descriptor *cmd; 467 struct usb2_cdc_acm_descriptor *cad; 468 469 *cm = *acm = 0; 470 471 cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 472 if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { 473 DPRINTF("no CM desc\n"); 474 return; 475 } 476 *cm = cmd->bmCapabilities; 477 478 cad = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); 479 if ((cad == NULL) || (cad->bLength < sizeof(*cad))) { 480 DPRINTF("no ACM desc\n"); 481 return; 482 } 483 *acm = cad->bmCapabilities; 484} 485 486static void 487umodem_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 488{ 489 struct umodem_softc *sc = ucom->sc_parent; 490 491 DPRINTF("\n"); 492 493 *lsr = sc->sc_lsr; 494 *msr = sc->sc_msr; 495} 496 497static int 498umodem_pre_param(struct usb2_com_softc *ucom, struct termios *t) 499{ 500 return (0); /* we accept anything */ 501} 502 503static void 504umodem_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 505{ 506 struct umodem_softc *sc = ucom->sc_parent; 507 struct usb2_cdc_line_state ls; 508 struct usb2_device_request req; 509 510 DPRINTF("sc=%p\n", sc); 511 512 bzero(&ls, sizeof(ls)); 513 514 USETDW(ls.dwDTERate, t->c_ospeed); 515 516 ls.bCharFormat = (t->c_cflag & CSTOPB) ? 517 UCDC_STOP_BIT_2 : UCDC_STOP_BIT_1; 518 519 ls.bParityType = (t->c_cflag & PARENB) ? 520 ((t->c_cflag & PARODD) ? 521 UCDC_PARITY_ODD : UCDC_PARITY_EVEN) : UCDC_PARITY_NONE; 522 523 switch (t->c_cflag & CSIZE) { 524 case CS5: 525 ls.bDataBits = 5; 526 break; 527 case CS6: 528 ls.bDataBits = 6; 529 break; 530 case CS7: 531 ls.bDataBits = 7; 532 break; 533 case CS8: 534 ls.bDataBits = 8; 535 break; 536 } 537 538 DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", 539 UGETDW(ls.dwDTERate), ls.bCharFormat, 540 ls.bParityType, ls.bDataBits); 541 542 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 543 req.bRequest = UCDC_SET_LINE_CODING; 544 USETW(req.wValue, 0); 545 req.wIndex[0] = sc->sc_ctrl_iface_no; 546 req.wIndex[1] = 0; 547 USETW(req.wLength, sizeof(ls)); 548 549 umodem_cfg_do_request(sc, &req, &ls); 550} 551 552static int 553umodem_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, 554 int flag, struct thread *td) 555{ 556 struct umodem_softc *sc = ucom->sc_parent; 557 int error = 0; 558 559 DPRINTF("cmd=0x%08x\n", cmd); 560 561 switch (cmd) { 562 case USB_GET_CM_OVER_DATA: 563 *(int *)data = sc->sc_cm_over_data; 564 break; 565 566 case USB_SET_CM_OVER_DATA: 567 if (*(int *)data != sc->sc_cm_over_data) { 568 /* XXX change it */ 569 } 570 break; 571 572 default: 573 DPRINTF("unknown\n"); 574 error = ENOIOCTL; 575 break; 576 } 577 578 return (error); 579} 580 581static void 582umodem_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 583{ 584 struct umodem_softc *sc = ucom->sc_parent; 585 struct usb2_device_request req; 586 587 DPRINTF("onoff=%d\n", onoff); 588 589 if (onoff) 590 sc->sc_line |= UCDC_LINE_DTR; 591 else 592 sc->sc_line &= ~UCDC_LINE_DTR; 593 594 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 595 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 596 USETW(req.wValue, sc->sc_line); 597 req.wIndex[0] = sc->sc_ctrl_iface_no; 598 req.wIndex[1] = 0; 599 USETW(req.wLength, 0); 600 601 umodem_cfg_do_request(sc, &req, NULL); 602} 603 604static void 605umodem_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 606{ 607 struct umodem_softc *sc = ucom->sc_parent; 608 struct usb2_device_request req; 609 610 DPRINTF("onoff=%d\n", onoff); 611 612 if (onoff) 613 sc->sc_line |= UCDC_LINE_RTS; 614 else 615 sc->sc_line &= ~UCDC_LINE_RTS; 616 617 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 618 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 619 USETW(req.wValue, sc->sc_line); 620 req.wIndex[0] = sc->sc_ctrl_iface_no; 621 req.wIndex[1] = 0; 622 USETW(req.wLength, 0); 623 624 umodem_cfg_do_request(sc, &req, NULL); 625} 626 627static void 628umodem_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 629{ 630 struct umodem_softc *sc = ucom->sc_parent; 631 struct usb2_device_request req; 632 uint16_t temp; 633 634 DPRINTF("onoff=%d\n", onoff); 635 636 if (sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK) { 637 638 temp = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF; 639 640 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 641 req.bRequest = UCDC_SEND_BREAK; 642 USETW(req.wValue, temp); 643 req.wIndex[0] = sc->sc_ctrl_iface_no; 644 req.wIndex[1] = 0; 645 USETW(req.wLength, 0); 646 647 umodem_cfg_do_request(sc, &req, NULL); 648 } 649} 650 651static void 652umodem_intr_callback(struct usb2_xfer *xfer) 653{ 654 struct usb2_cdc_notification pkt; 655 struct umodem_softc *sc = xfer->priv_sc; 656 uint16_t wLen; 657 658 switch (USB_GET_STATE(xfer)) { 659 case USB_ST_TRANSFERRED: 660 661 if (xfer->actlen < 8) { 662 DPRINTF("received short packet, " 663 "%d bytes\n", xfer->actlen); 664 goto tr_setup; 665 } 666 if (xfer->actlen > sizeof(pkt)) { 667 DPRINTF("truncating message\n"); 668 xfer->actlen = sizeof(pkt); 669 } 670 usb2_copy_out(xfer->frbuffers, 0, &pkt, xfer->actlen); 671 672 xfer->actlen -= 8; 673 674 wLen = UGETW(pkt.wLength); 675 if (xfer->actlen > wLen) { 676 xfer->actlen = wLen; 677 } 678 if (pkt.bmRequestType != UCDC_NOTIFICATION) { 679 DPRINTF("unknown message type, " 680 "0x%02x, on notify pipe!\n", 681 pkt.bmRequestType); 682 goto tr_setup; 683 } 684 switch (pkt.bNotification) { 685 case UCDC_N_SERIAL_STATE: 686 /* 687 * Set the serial state in ucom driver based on 688 * the bits from the notify message 689 */ 690 if (xfer->actlen < 2) { 691 DPRINTF("invalid notification " 692 "length, %d bytes!\n", xfer->actlen); 693 break; 694 } 695 DPRINTF("notify bytes = %02x%02x\n", 696 pkt.data[0], 697 pkt.data[1]); 698 699 /* Currently, lsr is always zero. */ 700 sc->sc_lsr = 0; 701 sc->sc_msr = 0; 702 703 if (pkt.data[0] & UCDC_N_SERIAL_RI) { 704 sc->sc_msr |= SER_RI; 705 } 706 if (pkt.data[0] & UCDC_N_SERIAL_DSR) { 707 sc->sc_msr |= SER_DSR; 708 } 709 if (pkt.data[0] & UCDC_N_SERIAL_DCD) { 710 sc->sc_msr |= SER_DCD; 711 } 712 usb2_com_status_change(&sc->sc_ucom); 713 break; 714 715 default: 716 DPRINTF("unknown notify message: 0x%02x\n", 717 pkt.bNotification); 718 break; 719 } 720 721 case USB_ST_SETUP: 722tr_setup: 723 if (sc->sc_flag & UMODEM_FLAG_INTR_STALL) { 724 usb2_transfer_start(sc->sc_xfer_intr[1]); 725 } else { 726 xfer->frlengths[0] = xfer->max_data_length; 727 usb2_start_hardware(xfer); 728 } 729 return; 730 731 default: /* Error */ 732 if (xfer->error != USB_ERR_CANCELLED) { 733 sc->sc_flag |= UMODEM_FLAG_INTR_STALL; 734 usb2_transfer_start(sc->sc_xfer_intr[1]); 735 } 736 return; 737 738 } 739} 740 741static void 742umodem_intr_clear_stall_callback(struct usb2_xfer *xfer) 743{ 744 struct umodem_softc *sc = xfer->priv_sc; 745 struct usb2_xfer *xfer_other = sc->sc_xfer_intr[0]; 746 747 if (usb2_clear_stall_callback(xfer, xfer_other)) { 748 DPRINTF("stall cleared\n"); 749 sc->sc_flag &= ~UMODEM_FLAG_INTR_STALL; 750 usb2_transfer_start(xfer_other); 751 } 752} 753 754static void 755umodem_write_callback(struct usb2_xfer *xfer) 756{ 757 struct umodem_softc *sc = xfer->priv_sc; 758 uint32_t actlen; 759 760 switch (USB_GET_STATE(xfer)) { 761 case USB_ST_SETUP: 762 case USB_ST_TRANSFERRED: 763 if (sc->sc_flag & UMODEM_FLAG_WRITE_STALL) { 764 usb2_transfer_start(sc->sc_xfer_data[2]); 765 return; 766 } 767 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 768 UMODEM_BUF_SIZE, &actlen)) { 769 770 xfer->frlengths[0] = actlen; 771 usb2_start_hardware(xfer); 772 } 773 return; 774 775 default: /* Error */ 776 if (xfer->error != USB_ERR_CANCELLED) { 777 sc->sc_flag |= UMODEM_FLAG_WRITE_STALL; 778 usb2_transfer_start(sc->sc_xfer_data[2]); 779 } 780 return; 781 782 } 783} 784 785static void 786umodem_write_clear_stall_callback(struct usb2_xfer *xfer) 787{ 788 struct umodem_softc *sc = xfer->priv_sc; 789 struct usb2_xfer *xfer_other = sc->sc_xfer_data[0]; 790 791 if (usb2_clear_stall_callback(xfer, xfer_other)) { 792 DPRINTF("stall cleared\n"); 793 sc->sc_flag &= ~UMODEM_FLAG_WRITE_STALL; 794 usb2_transfer_start(xfer_other); 795 } 796} 797 798static void 799umodem_read_callback(struct usb2_xfer *xfer) 800{ 801 struct umodem_softc *sc = xfer->priv_sc; 802 803 switch (USB_GET_STATE(xfer)) { 804 case USB_ST_TRANSFERRED: 805 806 DPRINTF("actlen=%d\n", xfer->actlen); 807 808 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, 809 xfer->actlen); 810 811 case USB_ST_SETUP: 812 if (sc->sc_flag & UMODEM_FLAG_READ_STALL) { 813 usb2_transfer_start(sc->sc_xfer_data[3]); 814 } else { 815 xfer->frlengths[0] = xfer->max_data_length; 816 usb2_start_hardware(xfer); 817 } 818 return; 819 820 default: /* Error */ 821 if (xfer->error != USB_ERR_CANCELLED) { 822 sc->sc_flag |= UMODEM_FLAG_READ_STALL; 823 usb2_transfer_start(sc->sc_xfer_data[3]); 824 } 825 return; 826 827 } 828} 829 830static void 831umodem_read_clear_stall_callback(struct usb2_xfer *xfer) 832{ 833 struct umodem_softc *sc = xfer->priv_sc; 834 struct usb2_xfer *xfer_other = sc->sc_xfer_data[1]; 835 836 if (usb2_clear_stall_callback(xfer, xfer_other)) { 837 DPRINTF("stall cleared\n"); 838 sc->sc_flag &= ~UMODEM_FLAG_READ_STALL; 839 usb2_transfer_start(xfer_other); 840 } 841} 842 843static void * 844umodem_get_desc(struct usb2_attach_arg *uaa, uint8_t type, uint8_t subtype) 845{ 846 return (usb2_find_descriptor(uaa->device, NULL, uaa->info.bIfaceIndex, 847 type, 0 - 1, subtype, 0 - 1)); 848} 849 850static usb2_error_t 851umodem_set_comm_feature(struct usb2_device *udev, uint8_t iface_no, 852 uint16_t feature, uint16_t state) 853{ 854 struct usb2_device_request req; 855 struct usb2_cdc_abstract_state ast; 856 857 DPRINTF("feature=%d state=%d\n", 858 feature, state); 859 860 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 861 req.bRequest = UCDC_SET_COMM_FEATURE; 862 USETW(req.wValue, feature); 863 req.wIndex[0] = iface_no; 864 req.wIndex[1] = 0; 865 USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH); 866 USETW(ast.wState, state); 867 868 return (usb2_do_request(udev, &Giant, &req, &ast)); 869} 870 871static int 872umodem_detach(device_t dev) 873{ 874 struct umodem_softc *sc = device_get_softc(dev); 875 876 DPRINTF("sc=%p\n", sc); 877 878 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 879 880 usb2_transfer_unsetup(sc->sc_xfer_intr, UMODEM_N_INTR_TRANSFER); 881 882 usb2_transfer_unsetup(sc->sc_xfer_data, UMODEM_N_DATA_TRANSFER); 883 884 return (0); 885} 886 887static void 888umodem_cfg_do_request(struct umodem_softc *sc, struct usb2_device_request *req, 889 void *data) 890{ 891 uint16_t length; 892 usb2_error_t err; 893 894 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 895 goto error; 896 } 897 err = usb2_do_request_flags(sc->sc_udev, &Giant, req, 898 data, 0, NULL, 1000); 899 900 if (err) { 901 902 DPRINTFN(0, "device request failed, err=%s " 903 "(ignored)\n", usb2_errstr(err)); 904 905error: 906 length = UGETW(req->wLength); 907 908 if ((req->bmRequestType & UT_READ) && length) { 909 bzero(data, length); 910 } 911 } 912}
| 95#include <dev/usb2/core/usb2_request.h> 96#include <dev/usb2/core/usb2_lookup.h> 97#include <dev/usb2/core/usb2_util.h> 98#include <dev/usb2/core/usb2_busdma.h> 99#include <dev/usb2/core/usb2_device.h> 100 101#include <dev/usb2/serial/usb2_serial.h> 102 103#if USB_DEBUG 104static int umodem_debug = 0; 105 106SYSCTL_NODE(_hw_usb2, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); 107SYSCTL_INT(_hw_usb2_umodem, OID_AUTO, debug, CTLFLAG_RW, 108 &umodem_debug, 0, "Debug level"); 109#endif 110 111static const struct usb2_device_id umodem_devs[] = { 112 /* Generic Modem class match */ 113 {USB_IFACE_CLASS(UICLASS_CDC), 114 USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), 115 USB_IFACE_PROTOCOL(UIPROTO_CDC_AT)}, 116 /* Kyocera AH-K3001V */ 117 {USB_VPI(USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_AHK3001V, 1)}, 118 {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, 1)}, 119 {USB_VPI(USB_VENDOR_CURITEL, USB_PRODUCT_CURITEL_PC5740, 1)}, 120}; 121 122/* 123 * As speeds for umodem deivces increase, these numbers will need to 124 * be increased. They should be good for G3 speeds and below. 125 * 126 * TODO: The TTY buffers should be increased! 127 */ 128#define UMODEM_BUF_SIZE 1024 129#define UMODEM_N_DATA_TRANSFER 4 130#define UMODEM_N_INTR_TRANSFER 2 131 132#define UMODEM_MODVER 1 /* module version */ 133 134struct umodem_softc { 135 struct usb2_com_super_softc sc_super_ucom; 136 struct usb2_com_softc sc_ucom; 137 138 struct usb2_xfer *sc_xfer_data[UMODEM_N_DATA_TRANSFER]; 139 struct usb2_xfer *sc_xfer_intr[UMODEM_N_INTR_TRANSFER]; 140 struct usb2_device *sc_udev; 141 142 uint16_t sc_line; 143 144 uint8_t sc_lsr; /* local status register */ 145 uint8_t sc_msr; /* modem status register */ 146 uint8_t sc_ctrl_iface_no; 147 uint8_t sc_ctrl_iface_index; 148 uint8_t sc_data_iface_no; 149 uint8_t sc_data_iface_index; 150 uint8_t sc_cm_over_data; 151 uint8_t sc_cm_cap; /* CM capabilities */ 152 uint8_t sc_acm_cap; /* ACM capabilities */ 153 uint8_t sc_flag; 154#define UMODEM_FLAG_READ_STALL 0x01 155#define UMODEM_FLAG_WRITE_STALL 0x02 156#define UMODEM_FLAG_INTR_STALL 0x04 157}; 158 159static device_probe_t umodem_probe; 160static device_attach_t umodem_attach; 161static device_detach_t umodem_detach; 162 163static usb2_callback_t umodem_intr_callback; 164static usb2_callback_t umodem_intr_clear_stall_callback; 165static usb2_callback_t umodem_write_callback; 166static usb2_callback_t umodem_read_callback; 167static usb2_callback_t umodem_write_clear_stall_callback; 168static usb2_callback_t umodem_read_clear_stall_callback; 169 170static void umodem_start_read(struct usb2_com_softc *); 171static void umodem_stop_read(struct usb2_com_softc *); 172static void umodem_start_write(struct usb2_com_softc *); 173static void umodem_stop_write(struct usb2_com_softc *); 174static void umodem_get_caps(struct usb2_attach_arg *, uint8_t *, uint8_t *); 175static void umodem_cfg_get_status(struct usb2_com_softc *, uint8_t *, 176 uint8_t *); 177static int umodem_pre_param(struct usb2_com_softc *, struct termios *); 178static void umodem_cfg_param(struct usb2_com_softc *, struct termios *); 179static int umodem_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int, 180 struct thread *); 181static void umodem_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 182static void umodem_cfg_set_rts(struct usb2_com_softc *, uint8_t); 183static void umodem_cfg_set_break(struct usb2_com_softc *, uint8_t); 184static void *umodem_get_desc(struct usb2_attach_arg *, uint8_t, uint8_t); 185static usb2_error_t umodem_set_comm_feature(struct usb2_device *, uint8_t, 186 uint16_t, uint16_t); 187static void umodem_cfg_do_request(struct umodem_softc *, 188 struct usb2_device_request *, void *); 189 190static const struct usb2_config umodem_config_data[UMODEM_N_DATA_TRANSFER] = { 191 192 [0] = { 193 .type = UE_BULK, 194 .endpoint = UE_ADDR_ANY, 195 .direction = UE_DIR_OUT, 196 .mh.bufsize = UMODEM_BUF_SIZE, 197 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 198 .mh.callback = &umodem_write_callback, 199 }, 200 201 [1] = { 202 .type = UE_BULK, 203 .endpoint = UE_ADDR_ANY, 204 .direction = UE_DIR_IN, 205 .mh.bufsize = UMODEM_BUF_SIZE, 206 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 207 .mh.callback = &umodem_read_callback, 208 }, 209 210 [2] = { 211 .type = UE_CONTROL, 212 .endpoint = 0x00, /* Control pipe */ 213 .direction = UE_DIR_ANY, 214 .mh.bufsize = sizeof(struct usb2_device_request), 215 .mh.callback = &umodem_write_clear_stall_callback, 216 .mh.timeout = 1000, /* 1 second */ 217 .mh.interval = 50, /* 50ms */ 218 }, 219 220 [3] = { 221 .type = UE_CONTROL, 222 .endpoint = 0x00, /* Control pipe */ 223 .direction = UE_DIR_ANY, 224 .mh.bufsize = sizeof(struct usb2_device_request), 225 .mh.callback = &umodem_read_clear_stall_callback, 226 .mh.timeout = 1000, /* 1 second */ 227 .mh.interval = 50, /* 50ms */ 228 }, 229}; 230 231static const struct usb2_config umodem_config_intr[UMODEM_N_INTR_TRANSFER] = { 232 [0] = { 233 .type = UE_INTERRUPT, 234 .endpoint = UE_ADDR_ANY, 235 .direction = UE_DIR_IN, 236 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 237 .mh.bufsize = 0, /* use wMaxPacketSize */ 238 .mh.callback = &umodem_intr_callback, 239 }, 240 241 [1] = { 242 .type = UE_CONTROL, 243 .endpoint = 0x00, /* Control pipe */ 244 .direction = UE_DIR_ANY, 245 .mh.bufsize = sizeof(struct usb2_device_request), 246 .mh.callback = &umodem_intr_clear_stall_callback, 247 .mh.timeout = 1000, /* 1 second */ 248 .mh.interval = 50, /* 50ms */ 249 }, 250}; 251 252static const struct usb2_com_callback umodem_callback = { 253 .usb2_com_cfg_get_status = &umodem_cfg_get_status, 254 .usb2_com_cfg_set_dtr = &umodem_cfg_set_dtr, 255 .usb2_com_cfg_set_rts = &umodem_cfg_set_rts, 256 .usb2_com_cfg_set_break = &umodem_cfg_set_break, 257 .usb2_com_cfg_param = &umodem_cfg_param, 258 .usb2_com_pre_param = &umodem_pre_param, 259 .usb2_com_ioctl = &umodem_ioctl, 260 .usb2_com_start_read = &umodem_start_read, 261 .usb2_com_stop_read = &umodem_stop_read, 262 .usb2_com_start_write = &umodem_start_write, 263 .usb2_com_stop_write = &umodem_stop_write, 264}; 265 266static device_method_t umodem_methods[] = { 267 DEVMETHOD(device_probe, umodem_probe), 268 DEVMETHOD(device_attach, umodem_attach), 269 DEVMETHOD(device_detach, umodem_detach), 270 {0, 0} 271}; 272 273static devclass_t umodem_devclass; 274 275static driver_t umodem_driver = { 276 .name = "umodem", 277 .methods = umodem_methods, 278 .size = sizeof(struct umodem_softc), 279}; 280 281DRIVER_MODULE(umodem, ushub, umodem_driver, umodem_devclass, NULL, 0); 282MODULE_DEPEND(umodem, usb2_serial, 1, 1, 1); 283MODULE_DEPEND(umodem, usb2_core, 1, 1, 1); 284MODULE_VERSION(umodem, UMODEM_MODVER); 285 286static int 287umodem_probe(device_t dev) 288{ 289 struct usb2_attach_arg *uaa = device_get_ivars(dev); 290 uint8_t cm; 291 uint8_t acm; 292 int error; 293 294 DPRINTFN(11, "\n"); 295 296 if (uaa->usb2_mode != USB_MODE_HOST) { 297 return (ENXIO); 298 } 299 error = usb2_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa); 300 if (error) { 301 return (error); 302 } 303 if (uaa->driver_info == NULL) { 304 /* some modems do not have any capabilities */ 305 return (error); 306 } 307 umodem_get_caps(uaa, &cm, &acm); 308 if (!(cm & USB_CDC_CM_DOES_CM) || 309 !(cm & USB_CDC_CM_OVER_DATA) || 310 !(acm & USB_CDC_ACM_HAS_LINE)) { 311 error = ENXIO; 312 } 313 return (error); 314} 315 316static int 317umodem_attach(device_t dev) 318{ 319 struct usb2_attach_arg *uaa = device_get_ivars(dev); 320 struct umodem_softc *sc = device_get_softc(dev); 321 struct usb2_cdc_cm_descriptor *cmd; 322 uint8_t i; 323 int error; 324 325 if (sc == NULL) { 326 return (ENOMEM); 327 } 328 device_set_usb2_desc(dev); 329 330 sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; 331 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex; 332 sc->sc_udev = uaa->device; 333 334 umodem_get_caps(uaa, &sc->sc_cm_cap, &sc->sc_acm_cap); 335 336 /* get the data interface number */ 337 338 cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 339 340 if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { 341 device_printf(dev, "no CM descriptor!\n"); 342 goto detach; 343 } 344 sc->sc_data_iface_no = cmd->bDataInterface; 345 346 device_printf(dev, "data interface %d, has %sCM over " 347 "data, has %sbreak\n", 348 sc->sc_data_iface_no, 349 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", 350 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); 351 352 /* get the data interface too */ 353 354 for (i = 0;; i++) { 355 struct usb2_interface *iface; 356 struct usb2_interface_descriptor *id; 357 358 iface = usb2_get_iface(uaa->device, i); 359 360 if (iface) { 361 362 id = usb2_get_interface_descriptor(iface); 363 364 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) { 365 sc->sc_data_iface_index = i; 366 usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 367 break; 368 } 369 } else { 370 device_printf(dev, "no data interface!\n"); 371 goto detach; 372 } 373 } 374 375 if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { 376 if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) { 377 378 error = umodem_set_comm_feature 379 (uaa->device, sc->sc_ctrl_iface_no, 380 UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); 381 382 /* ignore any errors */ 383 } 384 sc->sc_cm_over_data = 1; 385 } 386 error = usb2_transfer_setup(uaa->device, 387 &sc->sc_data_iface_index, sc->sc_xfer_data, 388 umodem_config_data, UMODEM_N_DATA_TRANSFER, 389 sc, &Giant); 390 if (error) { 391 goto detach; 392 } 393 error = usb2_transfer_setup(uaa->device, 394 &sc->sc_ctrl_iface_index, sc->sc_xfer_intr, 395 umodem_config_intr, UMODEM_N_INTR_TRANSFER, 396 sc, &Giant); 397 398 if (error == 0) { 399 device_printf(dev, "status change " 400 "notification available\n"); 401 } 402 /* clear stall at first run */ 403 sc->sc_flag |= (UMODEM_FLAG_READ_STALL | 404 UMODEM_FLAG_WRITE_STALL); 405 406 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 407 &umodem_callback, &Giant); 408 if (error) { 409 goto detach; 410 } 411 return (0); 412 413detach: 414 umodem_detach(dev); 415 return (ENXIO); 416} 417 418static void 419umodem_start_read(struct usb2_com_softc *ucom) 420{ 421 struct umodem_softc *sc = ucom->sc_parent; 422 423 if (sc->sc_xfer_intr[0]) { 424 /* start interrupt endpoint */ 425 usb2_transfer_start(sc->sc_xfer_intr[0]); 426 } 427 /* start read endpoint */ 428 usb2_transfer_start(sc->sc_xfer_data[1]); 429} 430 431static void 432umodem_stop_read(struct usb2_com_softc *ucom) 433{ 434 struct umodem_softc *sc = ucom->sc_parent; 435 436 if (sc->sc_xfer_intr[0]) { 437 /* stop interrupt endpoint */ 438 usb2_transfer_stop(sc->sc_xfer_intr[0]); 439 } 440 /* stop read endpoint */ 441 usb2_transfer_stop(sc->sc_xfer_data[3]); 442 usb2_transfer_stop(sc->sc_xfer_data[1]); 443} 444 445static void 446umodem_start_write(struct usb2_com_softc *ucom) 447{ 448 struct umodem_softc *sc = ucom->sc_parent; 449 450 usb2_transfer_start(sc->sc_xfer_data[0]); 451} 452 453static void 454umodem_stop_write(struct usb2_com_softc *ucom) 455{ 456 struct umodem_softc *sc = ucom->sc_parent; 457 458 usb2_transfer_stop(sc->sc_xfer_data[2]); 459 usb2_transfer_stop(sc->sc_xfer_data[0]); 460} 461 462static void 463umodem_get_caps(struct usb2_attach_arg *uaa, uint8_t *cm, uint8_t *acm) 464{ 465 struct usb2_cdc_cm_descriptor *cmd; 466 struct usb2_cdc_acm_descriptor *cad; 467 468 *cm = *acm = 0; 469 470 cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 471 if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { 472 DPRINTF("no CM desc\n"); 473 return; 474 } 475 *cm = cmd->bmCapabilities; 476 477 cad = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); 478 if ((cad == NULL) || (cad->bLength < sizeof(*cad))) { 479 DPRINTF("no ACM desc\n"); 480 return; 481 } 482 *acm = cad->bmCapabilities; 483} 484 485static void 486umodem_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 487{ 488 struct umodem_softc *sc = ucom->sc_parent; 489 490 DPRINTF("\n"); 491 492 *lsr = sc->sc_lsr; 493 *msr = sc->sc_msr; 494} 495 496static int 497umodem_pre_param(struct usb2_com_softc *ucom, struct termios *t) 498{ 499 return (0); /* we accept anything */ 500} 501 502static void 503umodem_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 504{ 505 struct umodem_softc *sc = ucom->sc_parent; 506 struct usb2_cdc_line_state ls; 507 struct usb2_device_request req; 508 509 DPRINTF("sc=%p\n", sc); 510 511 bzero(&ls, sizeof(ls)); 512 513 USETDW(ls.dwDTERate, t->c_ospeed); 514 515 ls.bCharFormat = (t->c_cflag & CSTOPB) ? 516 UCDC_STOP_BIT_2 : UCDC_STOP_BIT_1; 517 518 ls.bParityType = (t->c_cflag & PARENB) ? 519 ((t->c_cflag & PARODD) ? 520 UCDC_PARITY_ODD : UCDC_PARITY_EVEN) : UCDC_PARITY_NONE; 521 522 switch (t->c_cflag & CSIZE) { 523 case CS5: 524 ls.bDataBits = 5; 525 break; 526 case CS6: 527 ls.bDataBits = 6; 528 break; 529 case CS7: 530 ls.bDataBits = 7; 531 break; 532 case CS8: 533 ls.bDataBits = 8; 534 break; 535 } 536 537 DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", 538 UGETDW(ls.dwDTERate), ls.bCharFormat, 539 ls.bParityType, ls.bDataBits); 540 541 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 542 req.bRequest = UCDC_SET_LINE_CODING; 543 USETW(req.wValue, 0); 544 req.wIndex[0] = sc->sc_ctrl_iface_no; 545 req.wIndex[1] = 0; 546 USETW(req.wLength, sizeof(ls)); 547 548 umodem_cfg_do_request(sc, &req, &ls); 549} 550 551static int 552umodem_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, 553 int flag, struct thread *td) 554{ 555 struct umodem_softc *sc = ucom->sc_parent; 556 int error = 0; 557 558 DPRINTF("cmd=0x%08x\n", cmd); 559 560 switch (cmd) { 561 case USB_GET_CM_OVER_DATA: 562 *(int *)data = sc->sc_cm_over_data; 563 break; 564 565 case USB_SET_CM_OVER_DATA: 566 if (*(int *)data != sc->sc_cm_over_data) { 567 /* XXX change it */ 568 } 569 break; 570 571 default: 572 DPRINTF("unknown\n"); 573 error = ENOIOCTL; 574 break; 575 } 576 577 return (error); 578} 579 580static void 581umodem_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 582{ 583 struct umodem_softc *sc = ucom->sc_parent; 584 struct usb2_device_request req; 585 586 DPRINTF("onoff=%d\n", onoff); 587 588 if (onoff) 589 sc->sc_line |= UCDC_LINE_DTR; 590 else 591 sc->sc_line &= ~UCDC_LINE_DTR; 592 593 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 594 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 595 USETW(req.wValue, sc->sc_line); 596 req.wIndex[0] = sc->sc_ctrl_iface_no; 597 req.wIndex[1] = 0; 598 USETW(req.wLength, 0); 599 600 umodem_cfg_do_request(sc, &req, NULL); 601} 602 603static void 604umodem_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 605{ 606 struct umodem_softc *sc = ucom->sc_parent; 607 struct usb2_device_request req; 608 609 DPRINTF("onoff=%d\n", onoff); 610 611 if (onoff) 612 sc->sc_line |= UCDC_LINE_RTS; 613 else 614 sc->sc_line &= ~UCDC_LINE_RTS; 615 616 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 617 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 618 USETW(req.wValue, sc->sc_line); 619 req.wIndex[0] = sc->sc_ctrl_iface_no; 620 req.wIndex[1] = 0; 621 USETW(req.wLength, 0); 622 623 umodem_cfg_do_request(sc, &req, NULL); 624} 625 626static void 627umodem_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 628{ 629 struct umodem_softc *sc = ucom->sc_parent; 630 struct usb2_device_request req; 631 uint16_t temp; 632 633 DPRINTF("onoff=%d\n", onoff); 634 635 if (sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK) { 636 637 temp = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF; 638 639 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 640 req.bRequest = UCDC_SEND_BREAK; 641 USETW(req.wValue, temp); 642 req.wIndex[0] = sc->sc_ctrl_iface_no; 643 req.wIndex[1] = 0; 644 USETW(req.wLength, 0); 645 646 umodem_cfg_do_request(sc, &req, NULL); 647 } 648} 649 650static void 651umodem_intr_callback(struct usb2_xfer *xfer) 652{ 653 struct usb2_cdc_notification pkt; 654 struct umodem_softc *sc = xfer->priv_sc; 655 uint16_t wLen; 656 657 switch (USB_GET_STATE(xfer)) { 658 case USB_ST_TRANSFERRED: 659 660 if (xfer->actlen < 8) { 661 DPRINTF("received short packet, " 662 "%d bytes\n", xfer->actlen); 663 goto tr_setup; 664 } 665 if (xfer->actlen > sizeof(pkt)) { 666 DPRINTF("truncating message\n"); 667 xfer->actlen = sizeof(pkt); 668 } 669 usb2_copy_out(xfer->frbuffers, 0, &pkt, xfer->actlen); 670 671 xfer->actlen -= 8; 672 673 wLen = UGETW(pkt.wLength); 674 if (xfer->actlen > wLen) { 675 xfer->actlen = wLen; 676 } 677 if (pkt.bmRequestType != UCDC_NOTIFICATION) { 678 DPRINTF("unknown message type, " 679 "0x%02x, on notify pipe!\n", 680 pkt.bmRequestType); 681 goto tr_setup; 682 } 683 switch (pkt.bNotification) { 684 case UCDC_N_SERIAL_STATE: 685 /* 686 * Set the serial state in ucom driver based on 687 * the bits from the notify message 688 */ 689 if (xfer->actlen < 2) { 690 DPRINTF("invalid notification " 691 "length, %d bytes!\n", xfer->actlen); 692 break; 693 } 694 DPRINTF("notify bytes = %02x%02x\n", 695 pkt.data[0], 696 pkt.data[1]); 697 698 /* Currently, lsr is always zero. */ 699 sc->sc_lsr = 0; 700 sc->sc_msr = 0; 701 702 if (pkt.data[0] & UCDC_N_SERIAL_RI) { 703 sc->sc_msr |= SER_RI; 704 } 705 if (pkt.data[0] & UCDC_N_SERIAL_DSR) { 706 sc->sc_msr |= SER_DSR; 707 } 708 if (pkt.data[0] & UCDC_N_SERIAL_DCD) { 709 sc->sc_msr |= SER_DCD; 710 } 711 usb2_com_status_change(&sc->sc_ucom); 712 break; 713 714 default: 715 DPRINTF("unknown notify message: 0x%02x\n", 716 pkt.bNotification); 717 break; 718 } 719 720 case USB_ST_SETUP: 721tr_setup: 722 if (sc->sc_flag & UMODEM_FLAG_INTR_STALL) { 723 usb2_transfer_start(sc->sc_xfer_intr[1]); 724 } else { 725 xfer->frlengths[0] = xfer->max_data_length; 726 usb2_start_hardware(xfer); 727 } 728 return; 729 730 default: /* Error */ 731 if (xfer->error != USB_ERR_CANCELLED) { 732 sc->sc_flag |= UMODEM_FLAG_INTR_STALL; 733 usb2_transfer_start(sc->sc_xfer_intr[1]); 734 } 735 return; 736 737 } 738} 739 740static void 741umodem_intr_clear_stall_callback(struct usb2_xfer *xfer) 742{ 743 struct umodem_softc *sc = xfer->priv_sc; 744 struct usb2_xfer *xfer_other = sc->sc_xfer_intr[0]; 745 746 if (usb2_clear_stall_callback(xfer, xfer_other)) { 747 DPRINTF("stall cleared\n"); 748 sc->sc_flag &= ~UMODEM_FLAG_INTR_STALL; 749 usb2_transfer_start(xfer_other); 750 } 751} 752 753static void 754umodem_write_callback(struct usb2_xfer *xfer) 755{ 756 struct umodem_softc *sc = xfer->priv_sc; 757 uint32_t actlen; 758 759 switch (USB_GET_STATE(xfer)) { 760 case USB_ST_SETUP: 761 case USB_ST_TRANSFERRED: 762 if (sc->sc_flag & UMODEM_FLAG_WRITE_STALL) { 763 usb2_transfer_start(sc->sc_xfer_data[2]); 764 return; 765 } 766 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 767 UMODEM_BUF_SIZE, &actlen)) { 768 769 xfer->frlengths[0] = actlen; 770 usb2_start_hardware(xfer); 771 } 772 return; 773 774 default: /* Error */ 775 if (xfer->error != USB_ERR_CANCELLED) { 776 sc->sc_flag |= UMODEM_FLAG_WRITE_STALL; 777 usb2_transfer_start(sc->sc_xfer_data[2]); 778 } 779 return; 780 781 } 782} 783 784static void 785umodem_write_clear_stall_callback(struct usb2_xfer *xfer) 786{ 787 struct umodem_softc *sc = xfer->priv_sc; 788 struct usb2_xfer *xfer_other = sc->sc_xfer_data[0]; 789 790 if (usb2_clear_stall_callback(xfer, xfer_other)) { 791 DPRINTF("stall cleared\n"); 792 sc->sc_flag &= ~UMODEM_FLAG_WRITE_STALL; 793 usb2_transfer_start(xfer_other); 794 } 795} 796 797static void 798umodem_read_callback(struct usb2_xfer *xfer) 799{ 800 struct umodem_softc *sc = xfer->priv_sc; 801 802 switch (USB_GET_STATE(xfer)) { 803 case USB_ST_TRANSFERRED: 804 805 DPRINTF("actlen=%d\n", xfer->actlen); 806 807 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, 808 xfer->actlen); 809 810 case USB_ST_SETUP: 811 if (sc->sc_flag & UMODEM_FLAG_READ_STALL) { 812 usb2_transfer_start(sc->sc_xfer_data[3]); 813 } else { 814 xfer->frlengths[0] = xfer->max_data_length; 815 usb2_start_hardware(xfer); 816 } 817 return; 818 819 default: /* Error */ 820 if (xfer->error != USB_ERR_CANCELLED) { 821 sc->sc_flag |= UMODEM_FLAG_READ_STALL; 822 usb2_transfer_start(sc->sc_xfer_data[3]); 823 } 824 return; 825 826 } 827} 828 829static void 830umodem_read_clear_stall_callback(struct usb2_xfer *xfer) 831{ 832 struct umodem_softc *sc = xfer->priv_sc; 833 struct usb2_xfer *xfer_other = sc->sc_xfer_data[1]; 834 835 if (usb2_clear_stall_callback(xfer, xfer_other)) { 836 DPRINTF("stall cleared\n"); 837 sc->sc_flag &= ~UMODEM_FLAG_READ_STALL; 838 usb2_transfer_start(xfer_other); 839 } 840} 841 842static void * 843umodem_get_desc(struct usb2_attach_arg *uaa, uint8_t type, uint8_t subtype) 844{ 845 return (usb2_find_descriptor(uaa->device, NULL, uaa->info.bIfaceIndex, 846 type, 0 - 1, subtype, 0 - 1)); 847} 848 849static usb2_error_t 850umodem_set_comm_feature(struct usb2_device *udev, uint8_t iface_no, 851 uint16_t feature, uint16_t state) 852{ 853 struct usb2_device_request req; 854 struct usb2_cdc_abstract_state ast; 855 856 DPRINTF("feature=%d state=%d\n", 857 feature, state); 858 859 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 860 req.bRequest = UCDC_SET_COMM_FEATURE; 861 USETW(req.wValue, feature); 862 req.wIndex[0] = iface_no; 863 req.wIndex[1] = 0; 864 USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH); 865 USETW(ast.wState, state); 866 867 return (usb2_do_request(udev, &Giant, &req, &ast)); 868} 869 870static int 871umodem_detach(device_t dev) 872{ 873 struct umodem_softc *sc = device_get_softc(dev); 874 875 DPRINTF("sc=%p\n", sc); 876 877 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 878 879 usb2_transfer_unsetup(sc->sc_xfer_intr, UMODEM_N_INTR_TRANSFER); 880 881 usb2_transfer_unsetup(sc->sc_xfer_data, UMODEM_N_DATA_TRANSFER); 882 883 return (0); 884} 885 886static void 887umodem_cfg_do_request(struct umodem_softc *sc, struct usb2_device_request *req, 888 void *data) 889{ 890 uint16_t length; 891 usb2_error_t err; 892 893 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 894 goto error; 895 } 896 err = usb2_do_request_flags(sc->sc_udev, &Giant, req, 897 data, 0, NULL, 1000); 898 899 if (err) { 900 901 DPRINTFN(0, "device request failed, err=%s " 902 "(ignored)\n", usb2_errstr(err)); 903 904error: 905 length = UGETW(req->wLength); 906 907 if ((req->bmRequestType & UT_READ) && length) { 908 bzero(data, length); 909 } 910 } 911}
|