52#include <dev/usb2/core/usb2_request.h> 53#include <dev/usb2/core/usb2_lookup.h> 54#include <dev/usb2/core/usb2_util.h> 55#include <dev/usb2/core/usb2_busdma.h> 56 57#include <dev/usb2/serial/usb2_serial.h> 58 59#if USB_DEBUG 60static int uvscom_debug = 0; 61 62SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom"); 63SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW, 64 &uvscom_debug, 0, "Debug level"); 65#endif 66 67#define UVSCOM_MODVER 1 /* module version */ 68 69#define UVSCOM_CONFIG_INDEX 0 70#define UVSCOM_IFACE_INDEX 0 71 72/* Request */ 73#define UVSCOM_SET_SPEED 0x10 74#define UVSCOM_LINE_CTL 0x11 75#define UVSCOM_SET_PARAM 0x12 76#define UVSCOM_READ_STATUS 0xd0 77#define UVSCOM_SHUTDOWN 0xe0 78 79/* UVSCOM_SET_SPEED parameters */ 80#define UVSCOM_SPEED_150BPS 0x00 81#define UVSCOM_SPEED_300BPS 0x01 82#define UVSCOM_SPEED_600BPS 0x02 83#define UVSCOM_SPEED_1200BPS 0x03 84#define UVSCOM_SPEED_2400BPS 0x04 85#define UVSCOM_SPEED_4800BPS 0x05 86#define UVSCOM_SPEED_9600BPS 0x06 87#define UVSCOM_SPEED_19200BPS 0x07 88#define UVSCOM_SPEED_38400BPS 0x08 89#define UVSCOM_SPEED_57600BPS 0x09 90#define UVSCOM_SPEED_115200BPS 0x0a 91 92/* UVSCOM_LINE_CTL parameters */ 93#define UVSCOM_BREAK 0x40 94#define UVSCOM_RTS 0x02 95#define UVSCOM_DTR 0x01 96#define UVSCOM_LINE_INIT 0x08 97 98/* UVSCOM_SET_PARAM parameters */ 99#define UVSCOM_DATA_MASK 0x03 100#define UVSCOM_DATA_BIT_8 0x03 101#define UVSCOM_DATA_BIT_7 0x02 102#define UVSCOM_DATA_BIT_6 0x01 103#define UVSCOM_DATA_BIT_5 0x00 104 105#define UVSCOM_STOP_MASK 0x04 106#define UVSCOM_STOP_BIT_2 0x04 107#define UVSCOM_STOP_BIT_1 0x00 108 109#define UVSCOM_PARITY_MASK 0x18 110#define UVSCOM_PARITY_EVEN 0x18 111#define UVSCOM_PARITY_ODD 0x08 112#define UVSCOM_PARITY_NONE 0x00 113 114/* Status bits */ 115#define UVSCOM_TXRDY 0x04 116#define UVSCOM_RXRDY 0x01 117 118#define UVSCOM_DCD 0x08 119#define UVSCOM_NOCARD 0x04 120#define UVSCOM_DSR 0x02 121#define UVSCOM_CTS 0x01 122#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS) 123 124#define UVSCOM_BULK_BUF_SIZE 1024 /* bytes */ 125 126#define UVSCOM_N_TRANSFER 6 /* units */ 127 128struct uvscom_softc { 129 struct usb2_com_super_softc sc_super_ucom; 130 struct usb2_com_softc sc_ucom; 131 132 struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER]; 133 struct usb2_device *sc_udev; 134 135 uint16_t sc_line; /* line control register */ 136 137 uint8_t sc_flag; 138#define UVSCOM_FLAG_WRITE_STALL 0x0001 139#define UVSCOM_FLAG_READ_STALL 0x0002 140#define UVSCOM_FLAG_INTR_STALL 0x0004 141 uint8_t sc_iface_no; /* interface number */ 142 uint8_t sc_iface_index; /* interface index */ 143 uint8_t sc_lsr; /* local status register */ 144 uint8_t sc_msr; /* uvscom status register */ 145 uint8_t sc_unit_status; /* unit status */ 146}; 147 148/* prototypes */ 149 150static device_probe_t uvscom_probe; 151static device_attach_t uvscom_attach; 152static device_detach_t uvscom_detach; 153 154static usb2_callback_t uvscom_write_callback; 155static usb2_callback_t uvscom_write_clear_stall_callback; 156static usb2_callback_t uvscom_read_callback; 157static usb2_callback_t uvscom_read_clear_stall_callback; 158static usb2_callback_t uvscom_intr_callback; 159static usb2_callback_t uvscom_intr_clear_stall_callback; 160 161static void uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 162static void uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 163static void uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t); 164static int uvscom_pre_param(struct usb2_com_softc *, struct termios *); 165static void uvscom_cfg_param(struct usb2_com_softc *, struct termios *); 166static int uvscom_pre_open(struct usb2_com_softc *); 167static void uvscom_cfg_open(struct usb2_com_softc *); 168static void uvscom_cfg_close(struct usb2_com_softc *); 169static void uvscom_start_read(struct usb2_com_softc *); 170static void uvscom_stop_read(struct usb2_com_softc *); 171static void uvscom_start_write(struct usb2_com_softc *); 172static void uvscom_stop_write(struct usb2_com_softc *); 173static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 174 uint8_t *); 175static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t); 176static uint16_t uvscom_cfg_read_status(struct uvscom_softc *); 177 178static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = { 179 180 [0] = { 181 .type = UE_BULK, 182 .endpoint = UE_ADDR_ANY, 183 .direction = UE_DIR_OUT, 184 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 185 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 186 .mh.callback = &uvscom_write_callback, 187 }, 188 189 [1] = { 190 .type = UE_BULK, 191 .endpoint = UE_ADDR_ANY, 192 .direction = UE_DIR_IN, 193 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 194 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 195 .mh.callback = &uvscom_read_callback, 196 }, 197 198 [2] = { 199 .type = UE_CONTROL, 200 .endpoint = 0x00, /* Control pipe */ 201 .direction = UE_DIR_ANY, 202 .mh.bufsize = sizeof(struct usb2_device_request), 203 .mh.callback = &uvscom_write_clear_stall_callback, 204 .mh.timeout = 1000, /* 1 second */ 205 .mh.interval = 50, /* 50ms */ 206 }, 207 208 [3] = { 209 .type = UE_CONTROL, 210 .endpoint = 0x00, /* Control pipe */ 211 .direction = UE_DIR_ANY, 212 .mh.bufsize = sizeof(struct usb2_device_request), 213 .mh.callback = &uvscom_read_clear_stall_callback, 214 .mh.timeout = 1000, /* 1 second */ 215 .mh.interval = 50, /* 50ms */ 216 }, 217 218 [4] = { 219 .type = UE_INTERRUPT, 220 .endpoint = UE_ADDR_ANY, 221 .direction = UE_DIR_IN, 222 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 223 .mh.bufsize = 0, /* use wMaxPacketSize */ 224 .mh.callback = &uvscom_intr_callback, 225 }, 226 227 [5] = { 228 .type = UE_CONTROL, 229 .endpoint = 0x00, /* Control pipe */ 230 .direction = UE_DIR_ANY, 231 .mh.bufsize = sizeof(struct usb2_device_request), 232 .mh.callback = &uvscom_intr_clear_stall_callback, 233 .mh.timeout = 1000, /* 1 second */ 234 .mh.interval = 50, /* 50ms */ 235 }, 236}; 237 238static const struct usb2_com_callback uvscom_callback = { 239 .usb2_com_cfg_get_status = &uvscom_cfg_get_status, 240 .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr, 241 .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts, 242 .usb2_com_cfg_set_break = &uvscom_cfg_set_break, 243 .usb2_com_cfg_param = &uvscom_cfg_param, 244 .usb2_com_cfg_open = &uvscom_cfg_open, 245 .usb2_com_cfg_close = &uvscom_cfg_close, 246 .usb2_com_pre_open = &uvscom_pre_open, 247 .usb2_com_pre_param = &uvscom_pre_param, 248 .usb2_com_start_read = &uvscom_start_read, 249 .usb2_com_stop_read = &uvscom_stop_read, 250 .usb2_com_start_write = &uvscom_start_write, 251 .usb2_com_stop_write = &uvscom_stop_write, 252}; 253 254static const struct usb2_device_id uvscom_devs[] = { 255 /* SUNTAC U-Cable type A4 */ 256 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)}, 257 /* SUNTAC U-Cable type D2 */ 258 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)}, 259 /* SUNTAC Ir-Trinity */ 260 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)}, 261 /* SUNTAC U-Cable type P1 */ 262 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)}, 263 /* SUNTAC Slipper U */ 264 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)}, 265}; 266 267static device_method_t uvscom_methods[] = { 268 DEVMETHOD(device_probe, uvscom_probe), 269 DEVMETHOD(device_attach, uvscom_attach), 270 DEVMETHOD(device_detach, uvscom_detach), 271 {0, 0} 272}; 273 274static devclass_t uvscom_devclass; 275 276static driver_t uvscom_driver = { 277 .name = "uvscom", 278 .methods = uvscom_methods, 279 .size = sizeof(struct uvscom_softc), 280}; 281 282DRIVER_MODULE(uvscom, ushub, uvscom_driver, uvscom_devclass, NULL, 0); 283MODULE_DEPEND(uvscom, usb2_serial, 1, 1, 1); 284MODULE_DEPEND(uvscom, usb2_core, 1, 1, 1); 285MODULE_VERSION(uvscom, UVSCOM_MODVER); 286 287static int 288uvscom_probe(device_t dev) 289{ 290 struct usb2_attach_arg *uaa = device_get_ivars(dev); 291 292 if (uaa->usb2_mode != USB_MODE_HOST) { 293 return (ENXIO); 294 } 295 if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) { 296 return (ENXIO); 297 } 298 if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) { 299 return (ENXIO); 300 } 301 return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa)); 302} 303 304static int 305uvscom_attach(device_t dev) 306{ 307 struct usb2_attach_arg *uaa = device_get_ivars(dev); 308 struct uvscom_softc *sc = device_get_softc(dev); 309 int error; 310 311 if (sc == NULL) { 312 return (ENOMEM); 313 } 314 device_set_usb2_desc(dev); 315 316 sc->sc_udev = uaa->device; 317 318 DPRINTF("sc=%p\n", sc); 319 320 sc->sc_iface_no = uaa->info.bIfaceNum; 321 sc->sc_iface_index = UVSCOM_IFACE_INDEX; 322 323 error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index, 324 sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &Giant); 325 326 if (error) { 327 DPRINTF("could not allocate all USB transfers!\n"); 328 goto detach; 329 } 330 sc->sc_line = UVSCOM_LINE_INIT; 331 332 /* clear stall at first run */ 333 sc->sc_flag |= (UVSCOM_FLAG_WRITE_STALL | 334 UVSCOM_FLAG_READ_STALL); 335 336 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 337 &uvscom_callback, &Giant); 338 if (error) { 339 goto detach; 340 } 341 /* start interrupt pipe */ 342 mtx_lock(&Giant); 343 usb2_transfer_start(sc->sc_xfer[4]); 344 mtx_unlock(&Giant); 345 346 return (0); 347 348detach: 349 uvscom_detach(dev); 350 return (ENXIO); 351} 352 353static int 354uvscom_detach(device_t dev) 355{ 356 struct uvscom_softc *sc = device_get_softc(dev); 357 358 DPRINTF("sc=%p\n", sc); 359 360 /* stop interrupt pipe */ 361 362 if (sc->sc_xfer[4]) { 363 usb2_transfer_stop(sc->sc_xfer[4]); 364 } 365 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 366 367 usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER); 368 369 return (0); 370} 371 372static void 373uvscom_write_callback(struct usb2_xfer *xfer) 374{ 375 struct uvscom_softc *sc = xfer->priv_sc; 376 uint32_t actlen; 377 378 switch (USB_GET_STATE(xfer)) { 379 case USB_ST_SETUP: 380 case USB_ST_TRANSFERRED: 381 if (sc->sc_flag & UVSCOM_FLAG_WRITE_STALL) { 382 usb2_transfer_start(sc->sc_xfer[2]); 383 return; 384 } 385 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 386 UVSCOM_BULK_BUF_SIZE, &actlen)) { 387 388 xfer->frlengths[0] = actlen; 389 usb2_start_hardware(xfer); 390 } 391 return; 392 393 default: /* Error */ 394 if (xfer->error != USB_ERR_CANCELLED) { 395 sc->sc_flag |= UVSCOM_FLAG_WRITE_STALL; 396 usb2_transfer_start(sc->sc_xfer[2]); 397 } 398 return; 399 400 } 401} 402 403static void 404uvscom_write_clear_stall_callback(struct usb2_xfer *xfer) 405{ 406 struct uvscom_softc *sc = xfer->priv_sc; 407 struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 408 409 if (usb2_clear_stall_callback(xfer, xfer_other)) { 410 DPRINTF("stall cleared\n"); 411 sc->sc_flag &= ~UVSCOM_FLAG_WRITE_STALL; 412 usb2_transfer_start(xfer_other); 413 } 414} 415 416static void 417uvscom_read_callback(struct usb2_xfer *xfer) 418{ 419 struct uvscom_softc *sc = xfer->priv_sc; 420 421 switch (USB_GET_STATE(xfer)) { 422 case USB_ST_TRANSFERRED: 423 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 424 425 case USB_ST_SETUP: 426 if (sc->sc_flag & UVSCOM_FLAG_READ_STALL) { 427 usb2_transfer_start(sc->sc_xfer[3]); 428 } else { 429 xfer->frlengths[0] = xfer->max_data_length; 430 usb2_start_hardware(xfer); 431 } 432 return; 433 434 default: /* Error */ 435 if (xfer->error != USB_ERR_CANCELLED) { 436 sc->sc_flag |= UVSCOM_FLAG_READ_STALL; 437 usb2_transfer_start(sc->sc_xfer[3]); 438 } 439 return; 440 441 } 442} 443 444static void 445uvscom_read_clear_stall_callback(struct usb2_xfer *xfer) 446{ 447 struct uvscom_softc *sc = xfer->priv_sc; 448 struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 449 450 if (usb2_clear_stall_callback(xfer, xfer_other)) { 451 DPRINTF("stall cleared\n"); 452 sc->sc_flag &= ~UVSCOM_FLAG_READ_STALL; 453 usb2_transfer_start(xfer_other); 454 } 455} 456 457static void 458uvscom_intr_callback(struct usb2_xfer *xfer) 459{ 460 struct uvscom_softc *sc = xfer->priv_sc; 461 uint8_t buf[2]; 462 463 switch (USB_GET_STATE(xfer)) { 464 case USB_ST_TRANSFERRED: 465 if (xfer->actlen >= 2) { 466 467 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 468 469 sc->sc_lsr = 0; 470 sc->sc_msr = 0; 471 sc->sc_unit_status = buf[1]; 472 473 if (buf[0] & UVSCOM_TXRDY) { 474 sc->sc_lsr |= ULSR_TXRDY; 475 } 476 if (buf[0] & UVSCOM_RXRDY) { 477 sc->sc_lsr |= ULSR_RXRDY; 478 } 479 if (buf[1] & UVSCOM_CTS) { 480 sc->sc_msr |= SER_CTS; 481 } 482 if (buf[1] & UVSCOM_DSR) { 483 sc->sc_msr |= SER_DSR; 484 } 485 if (buf[1] & UVSCOM_DCD) { 486 sc->sc_msr |= SER_DCD; 487 } 488 /* 489 * the UCOM layer will ignore this call if the TTY 490 * device is closed! 491 */ 492 usb2_com_status_change(&sc->sc_ucom); 493 } 494 case USB_ST_SETUP: 495 if (sc->sc_flag & UVSCOM_FLAG_INTR_STALL) { 496 usb2_transfer_start(sc->sc_xfer[5]); 497 } else { 498 xfer->frlengths[0] = xfer->max_data_length; 499 usb2_start_hardware(xfer); 500 } 501 return; 502 503 default: /* Error */ 504 if (xfer->error != USB_ERR_CANCELLED) { 505 sc->sc_flag |= UVSCOM_FLAG_INTR_STALL; 506 usb2_transfer_start(sc->sc_xfer[5]); 507 } 508 return; 509 510 } 511} 512 513static void 514uvscom_intr_clear_stall_callback(struct usb2_xfer *xfer) 515{ 516 struct uvscom_softc *sc = xfer->priv_sc; 517 struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 518 519 if (usb2_clear_stall_callback(xfer, xfer_other)) { 520 DPRINTF("stall cleared\n"); 521 sc->sc_flag &= ~UVSCOM_FLAG_INTR_STALL; 522 usb2_transfer_start(xfer_other); 523 } 524} 525 526static void 527uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 528{ 529 struct uvscom_softc *sc = ucom->sc_parent; 530 531 DPRINTF("onoff = %d\n", onoff); 532 533 if (onoff) 534 sc->sc_line |= UVSCOM_DTR; 535 else 536 sc->sc_line &= ~UVSCOM_DTR; 537 538 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 539} 540 541static void 542uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 543{ 544 struct uvscom_softc *sc = ucom->sc_parent; 545 546 DPRINTF("onoff = %d\n", onoff); 547 548 if (onoff) 549 sc->sc_line |= UVSCOM_RTS; 550 else 551 sc->sc_line &= ~UVSCOM_RTS; 552 553 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 554} 555 556static void 557uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 558{ 559 struct uvscom_softc *sc = ucom->sc_parent; 560 561 DPRINTF("onoff = %d\n", onoff); 562 563 if (onoff) 564 sc->sc_line |= UVSCOM_BREAK; 565 else 566 sc->sc_line &= ~UVSCOM_BREAK; 567 568 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 569} 570 571static int 572uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 573{ 574 switch (t->c_ospeed) { 575 case B150: 576 case B300: 577 case B600: 578 case B1200: 579 case B2400: 580 case B4800: 581 case B9600: 582 case B19200: 583 case B38400: 584 case B57600: 585 case B115200: 586 default: 587 return (EINVAL); 588 } 589 return (0); 590} 591 592static void 593uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 594{ 595 struct uvscom_softc *sc = ucom->sc_parent; 596 uint16_t value; 597 598 DPRINTF("\n"); 599 600 switch (t->c_ospeed) { 601 case B150: 602 value = UVSCOM_SPEED_150BPS; 603 break; 604 case B300: 605 value = UVSCOM_SPEED_300BPS; 606 break; 607 case B600: 608 value = UVSCOM_SPEED_600BPS; 609 break; 610 case B1200: 611 value = UVSCOM_SPEED_1200BPS; 612 break; 613 case B2400: 614 value = UVSCOM_SPEED_2400BPS; 615 break; 616 case B4800: 617 value = UVSCOM_SPEED_4800BPS; 618 break; 619 case B9600: 620 value = UVSCOM_SPEED_9600BPS; 621 break; 622 case B19200: 623 value = UVSCOM_SPEED_19200BPS; 624 break; 625 case B38400: 626 value = UVSCOM_SPEED_38400BPS; 627 break; 628 case B57600: 629 value = UVSCOM_SPEED_57600BPS; 630 break; 631 case B115200: 632 value = UVSCOM_SPEED_115200BPS; 633 break; 634 default: 635 return; 636 } 637 638 uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value); 639 640 value = 0; 641 642 if (t->c_cflag & CSTOPB) { 643 value |= UVSCOM_STOP_BIT_2; 644 } 645 if (t->c_cflag & PARENB) { 646 if (t->c_cflag & PARODD) { 647 value |= UVSCOM_PARITY_ODD; 648 } else { 649 value |= UVSCOM_PARITY_EVEN; 650 } 651 } else { 652 value |= UVSCOM_PARITY_NONE; 653 } 654 655 switch (t->c_cflag & CSIZE) { 656 case CS5: 657 value |= UVSCOM_DATA_BIT_5; 658 break; 659 case CS6: 660 value |= UVSCOM_DATA_BIT_6; 661 break; 662 case CS7: 663 value |= UVSCOM_DATA_BIT_7; 664 break; 665 default: 666 case CS8: 667 value |= UVSCOM_DATA_BIT_8; 668 break; 669 } 670 671 uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value); 672} 673 674static int 675uvscom_pre_open(struct usb2_com_softc *ucom) 676{ 677 struct uvscom_softc *sc = ucom->sc_parent; 678 679 DPRINTF("sc = %p\n", sc); 680 681 /* check if PC card was inserted */ 682 683 if (sc->sc_unit_status & UVSCOM_NOCARD) { 684 DPRINTF("no PC card!\n"); 685 return (ENXIO); 686 } 687 return (0); 688} 689 690static void 691uvscom_cfg_open(struct usb2_com_softc *ucom) 692{ 693 struct uvscom_softc *sc = ucom->sc_parent; 694 695 DPRINTF("sc = %p\n", sc); 696 697 uvscom_cfg_read_status(sc); 698} 699 700static void 701uvscom_cfg_close(struct usb2_com_softc *ucom) 702{ 703 struct uvscom_softc *sc = ucom->sc_parent; 704 705 DPRINTF("sc=%p\n", sc); 706 707 uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0); 708} 709 710static void 711uvscom_start_read(struct usb2_com_softc *ucom) 712{ 713 struct uvscom_softc *sc = ucom->sc_parent; 714 715 usb2_transfer_start(sc->sc_xfer[1]); 716} 717 718static void 719uvscom_stop_read(struct usb2_com_softc *ucom) 720{ 721 struct uvscom_softc *sc = ucom->sc_parent; 722 723 usb2_transfer_stop(sc->sc_xfer[3]); 724 usb2_transfer_stop(sc->sc_xfer[1]); 725} 726 727static void 728uvscom_start_write(struct usb2_com_softc *ucom) 729{ 730 struct uvscom_softc *sc = ucom->sc_parent; 731 732 usb2_transfer_start(sc->sc_xfer[0]); 733} 734 735static void 736uvscom_stop_write(struct usb2_com_softc *ucom) 737{ 738 struct uvscom_softc *sc = ucom->sc_parent; 739 740 usb2_transfer_stop(sc->sc_xfer[2]); 741 usb2_transfer_stop(sc->sc_xfer[0]); 742} 743 744static void 745uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 746{ 747 struct uvscom_softc *sc = ucom->sc_parent; 748 749 *lsr = sc->sc_lsr; 750 *msr = sc->sc_msr; 751} 752 753static void 754uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value) 755{ 756 struct usb2_device_request req; 757 usb2_error_t err; 758 759 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 760 return; 761 } 762 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 763 req.bRequest = index; 764 USETW(req.wValue, value); 765 USETW(req.wIndex, 0); 766 USETW(req.wLength, 0); 767 768 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 769 NULL, 0, NULL, 1000); 770 if (err) { 771 DPRINTFN(0, "device request failed, err=%s " 772 "(ignored)\n", usb2_errstr(err)); 773 } 774} 775 776static uint16_t 777uvscom_cfg_read_status(struct uvscom_softc *sc) 778{ 779 struct usb2_device_request req; 780 usb2_error_t err; 781 uint8_t data[2]; 782 783 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 784 return (0); 785 } 786 req.bmRequestType = UT_READ_VENDOR_DEVICE; 787 req.bRequest = UVSCOM_READ_STATUS; 788 USETW(req.wValue, 0); 789 USETW(req.wIndex, 0); 790 USETW(req.wLength, 2); 791 792 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 793 data, 0, NULL, 1000); 794 if (err) { 795 DPRINTFN(0, "device request failed, err=%s " 796 "(ignored)\n", usb2_errstr(err)); 797 data[0] = 0; 798 data[1] = 0; 799 } 800 return (data[0] | (data[1] << 8)); 801}
| 51#include <dev/usb2/core/usb2_request.h> 52#include <dev/usb2/core/usb2_lookup.h> 53#include <dev/usb2/core/usb2_util.h> 54#include <dev/usb2/core/usb2_busdma.h> 55 56#include <dev/usb2/serial/usb2_serial.h> 57 58#if USB_DEBUG 59static int uvscom_debug = 0; 60 61SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom"); 62SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW, 63 &uvscom_debug, 0, "Debug level"); 64#endif 65 66#define UVSCOM_MODVER 1 /* module version */ 67 68#define UVSCOM_CONFIG_INDEX 0 69#define UVSCOM_IFACE_INDEX 0 70 71/* Request */ 72#define UVSCOM_SET_SPEED 0x10 73#define UVSCOM_LINE_CTL 0x11 74#define UVSCOM_SET_PARAM 0x12 75#define UVSCOM_READ_STATUS 0xd0 76#define UVSCOM_SHUTDOWN 0xe0 77 78/* UVSCOM_SET_SPEED parameters */ 79#define UVSCOM_SPEED_150BPS 0x00 80#define UVSCOM_SPEED_300BPS 0x01 81#define UVSCOM_SPEED_600BPS 0x02 82#define UVSCOM_SPEED_1200BPS 0x03 83#define UVSCOM_SPEED_2400BPS 0x04 84#define UVSCOM_SPEED_4800BPS 0x05 85#define UVSCOM_SPEED_9600BPS 0x06 86#define UVSCOM_SPEED_19200BPS 0x07 87#define UVSCOM_SPEED_38400BPS 0x08 88#define UVSCOM_SPEED_57600BPS 0x09 89#define UVSCOM_SPEED_115200BPS 0x0a 90 91/* UVSCOM_LINE_CTL parameters */ 92#define UVSCOM_BREAK 0x40 93#define UVSCOM_RTS 0x02 94#define UVSCOM_DTR 0x01 95#define UVSCOM_LINE_INIT 0x08 96 97/* UVSCOM_SET_PARAM parameters */ 98#define UVSCOM_DATA_MASK 0x03 99#define UVSCOM_DATA_BIT_8 0x03 100#define UVSCOM_DATA_BIT_7 0x02 101#define UVSCOM_DATA_BIT_6 0x01 102#define UVSCOM_DATA_BIT_5 0x00 103 104#define UVSCOM_STOP_MASK 0x04 105#define UVSCOM_STOP_BIT_2 0x04 106#define UVSCOM_STOP_BIT_1 0x00 107 108#define UVSCOM_PARITY_MASK 0x18 109#define UVSCOM_PARITY_EVEN 0x18 110#define UVSCOM_PARITY_ODD 0x08 111#define UVSCOM_PARITY_NONE 0x00 112 113/* Status bits */ 114#define UVSCOM_TXRDY 0x04 115#define UVSCOM_RXRDY 0x01 116 117#define UVSCOM_DCD 0x08 118#define UVSCOM_NOCARD 0x04 119#define UVSCOM_DSR 0x02 120#define UVSCOM_CTS 0x01 121#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS) 122 123#define UVSCOM_BULK_BUF_SIZE 1024 /* bytes */ 124 125#define UVSCOM_N_TRANSFER 6 /* units */ 126 127struct uvscom_softc { 128 struct usb2_com_super_softc sc_super_ucom; 129 struct usb2_com_softc sc_ucom; 130 131 struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER]; 132 struct usb2_device *sc_udev; 133 134 uint16_t sc_line; /* line control register */ 135 136 uint8_t sc_flag; 137#define UVSCOM_FLAG_WRITE_STALL 0x0001 138#define UVSCOM_FLAG_READ_STALL 0x0002 139#define UVSCOM_FLAG_INTR_STALL 0x0004 140 uint8_t sc_iface_no; /* interface number */ 141 uint8_t sc_iface_index; /* interface index */ 142 uint8_t sc_lsr; /* local status register */ 143 uint8_t sc_msr; /* uvscom status register */ 144 uint8_t sc_unit_status; /* unit status */ 145}; 146 147/* prototypes */ 148 149static device_probe_t uvscom_probe; 150static device_attach_t uvscom_attach; 151static device_detach_t uvscom_detach; 152 153static usb2_callback_t uvscom_write_callback; 154static usb2_callback_t uvscom_write_clear_stall_callback; 155static usb2_callback_t uvscom_read_callback; 156static usb2_callback_t uvscom_read_clear_stall_callback; 157static usb2_callback_t uvscom_intr_callback; 158static usb2_callback_t uvscom_intr_clear_stall_callback; 159 160static void uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 161static void uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 162static void uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t); 163static int uvscom_pre_param(struct usb2_com_softc *, struct termios *); 164static void uvscom_cfg_param(struct usb2_com_softc *, struct termios *); 165static int uvscom_pre_open(struct usb2_com_softc *); 166static void uvscom_cfg_open(struct usb2_com_softc *); 167static void uvscom_cfg_close(struct usb2_com_softc *); 168static void uvscom_start_read(struct usb2_com_softc *); 169static void uvscom_stop_read(struct usb2_com_softc *); 170static void uvscom_start_write(struct usb2_com_softc *); 171static void uvscom_stop_write(struct usb2_com_softc *); 172static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 173 uint8_t *); 174static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t); 175static uint16_t uvscom_cfg_read_status(struct uvscom_softc *); 176 177static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = { 178 179 [0] = { 180 .type = UE_BULK, 181 .endpoint = UE_ADDR_ANY, 182 .direction = UE_DIR_OUT, 183 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 184 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 185 .mh.callback = &uvscom_write_callback, 186 }, 187 188 [1] = { 189 .type = UE_BULK, 190 .endpoint = UE_ADDR_ANY, 191 .direction = UE_DIR_IN, 192 .mh.bufsize = UVSCOM_BULK_BUF_SIZE, 193 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 194 .mh.callback = &uvscom_read_callback, 195 }, 196 197 [2] = { 198 .type = UE_CONTROL, 199 .endpoint = 0x00, /* Control pipe */ 200 .direction = UE_DIR_ANY, 201 .mh.bufsize = sizeof(struct usb2_device_request), 202 .mh.callback = &uvscom_write_clear_stall_callback, 203 .mh.timeout = 1000, /* 1 second */ 204 .mh.interval = 50, /* 50ms */ 205 }, 206 207 [3] = { 208 .type = UE_CONTROL, 209 .endpoint = 0x00, /* Control pipe */ 210 .direction = UE_DIR_ANY, 211 .mh.bufsize = sizeof(struct usb2_device_request), 212 .mh.callback = &uvscom_read_clear_stall_callback, 213 .mh.timeout = 1000, /* 1 second */ 214 .mh.interval = 50, /* 50ms */ 215 }, 216 217 [4] = { 218 .type = UE_INTERRUPT, 219 .endpoint = UE_ADDR_ANY, 220 .direction = UE_DIR_IN, 221 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 222 .mh.bufsize = 0, /* use wMaxPacketSize */ 223 .mh.callback = &uvscom_intr_callback, 224 }, 225 226 [5] = { 227 .type = UE_CONTROL, 228 .endpoint = 0x00, /* Control pipe */ 229 .direction = UE_DIR_ANY, 230 .mh.bufsize = sizeof(struct usb2_device_request), 231 .mh.callback = &uvscom_intr_clear_stall_callback, 232 .mh.timeout = 1000, /* 1 second */ 233 .mh.interval = 50, /* 50ms */ 234 }, 235}; 236 237static const struct usb2_com_callback uvscom_callback = { 238 .usb2_com_cfg_get_status = &uvscom_cfg_get_status, 239 .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr, 240 .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts, 241 .usb2_com_cfg_set_break = &uvscom_cfg_set_break, 242 .usb2_com_cfg_param = &uvscom_cfg_param, 243 .usb2_com_cfg_open = &uvscom_cfg_open, 244 .usb2_com_cfg_close = &uvscom_cfg_close, 245 .usb2_com_pre_open = &uvscom_pre_open, 246 .usb2_com_pre_param = &uvscom_pre_param, 247 .usb2_com_start_read = &uvscom_start_read, 248 .usb2_com_stop_read = &uvscom_stop_read, 249 .usb2_com_start_write = &uvscom_start_write, 250 .usb2_com_stop_write = &uvscom_stop_write, 251}; 252 253static const struct usb2_device_id uvscom_devs[] = { 254 /* SUNTAC U-Cable type A4 */ 255 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)}, 256 /* SUNTAC U-Cable type D2 */ 257 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)}, 258 /* SUNTAC Ir-Trinity */ 259 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)}, 260 /* SUNTAC U-Cable type P1 */ 261 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)}, 262 /* SUNTAC Slipper U */ 263 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)}, 264}; 265 266static device_method_t uvscom_methods[] = { 267 DEVMETHOD(device_probe, uvscom_probe), 268 DEVMETHOD(device_attach, uvscom_attach), 269 DEVMETHOD(device_detach, uvscom_detach), 270 {0, 0} 271}; 272 273static devclass_t uvscom_devclass; 274 275static driver_t uvscom_driver = { 276 .name = "uvscom", 277 .methods = uvscom_methods, 278 .size = sizeof(struct uvscom_softc), 279}; 280 281DRIVER_MODULE(uvscom, ushub, uvscom_driver, uvscom_devclass, NULL, 0); 282MODULE_DEPEND(uvscom, usb2_serial, 1, 1, 1); 283MODULE_DEPEND(uvscom, usb2_core, 1, 1, 1); 284MODULE_VERSION(uvscom, UVSCOM_MODVER); 285 286static int 287uvscom_probe(device_t dev) 288{ 289 struct usb2_attach_arg *uaa = device_get_ivars(dev); 290 291 if (uaa->usb2_mode != USB_MODE_HOST) { 292 return (ENXIO); 293 } 294 if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) { 295 return (ENXIO); 296 } 297 if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) { 298 return (ENXIO); 299 } 300 return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa)); 301} 302 303static int 304uvscom_attach(device_t dev) 305{ 306 struct usb2_attach_arg *uaa = device_get_ivars(dev); 307 struct uvscom_softc *sc = device_get_softc(dev); 308 int error; 309 310 if (sc == NULL) { 311 return (ENOMEM); 312 } 313 device_set_usb2_desc(dev); 314 315 sc->sc_udev = uaa->device; 316 317 DPRINTF("sc=%p\n", sc); 318 319 sc->sc_iface_no = uaa->info.bIfaceNum; 320 sc->sc_iface_index = UVSCOM_IFACE_INDEX; 321 322 error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index, 323 sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &Giant); 324 325 if (error) { 326 DPRINTF("could not allocate all USB transfers!\n"); 327 goto detach; 328 } 329 sc->sc_line = UVSCOM_LINE_INIT; 330 331 /* clear stall at first run */ 332 sc->sc_flag |= (UVSCOM_FLAG_WRITE_STALL | 333 UVSCOM_FLAG_READ_STALL); 334 335 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 336 &uvscom_callback, &Giant); 337 if (error) { 338 goto detach; 339 } 340 /* start interrupt pipe */ 341 mtx_lock(&Giant); 342 usb2_transfer_start(sc->sc_xfer[4]); 343 mtx_unlock(&Giant); 344 345 return (0); 346 347detach: 348 uvscom_detach(dev); 349 return (ENXIO); 350} 351 352static int 353uvscom_detach(device_t dev) 354{ 355 struct uvscom_softc *sc = device_get_softc(dev); 356 357 DPRINTF("sc=%p\n", sc); 358 359 /* stop interrupt pipe */ 360 361 if (sc->sc_xfer[4]) { 362 usb2_transfer_stop(sc->sc_xfer[4]); 363 } 364 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 365 366 usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER); 367 368 return (0); 369} 370 371static void 372uvscom_write_callback(struct usb2_xfer *xfer) 373{ 374 struct uvscom_softc *sc = xfer->priv_sc; 375 uint32_t actlen; 376 377 switch (USB_GET_STATE(xfer)) { 378 case USB_ST_SETUP: 379 case USB_ST_TRANSFERRED: 380 if (sc->sc_flag & UVSCOM_FLAG_WRITE_STALL) { 381 usb2_transfer_start(sc->sc_xfer[2]); 382 return; 383 } 384 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 385 UVSCOM_BULK_BUF_SIZE, &actlen)) { 386 387 xfer->frlengths[0] = actlen; 388 usb2_start_hardware(xfer); 389 } 390 return; 391 392 default: /* Error */ 393 if (xfer->error != USB_ERR_CANCELLED) { 394 sc->sc_flag |= UVSCOM_FLAG_WRITE_STALL; 395 usb2_transfer_start(sc->sc_xfer[2]); 396 } 397 return; 398 399 } 400} 401 402static void 403uvscom_write_clear_stall_callback(struct usb2_xfer *xfer) 404{ 405 struct uvscom_softc *sc = xfer->priv_sc; 406 struct usb2_xfer *xfer_other = sc->sc_xfer[0]; 407 408 if (usb2_clear_stall_callback(xfer, xfer_other)) { 409 DPRINTF("stall cleared\n"); 410 sc->sc_flag &= ~UVSCOM_FLAG_WRITE_STALL; 411 usb2_transfer_start(xfer_other); 412 } 413} 414 415static void 416uvscom_read_callback(struct usb2_xfer *xfer) 417{ 418 struct uvscom_softc *sc = xfer->priv_sc; 419 420 switch (USB_GET_STATE(xfer)) { 421 case USB_ST_TRANSFERRED: 422 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 423 424 case USB_ST_SETUP: 425 if (sc->sc_flag & UVSCOM_FLAG_READ_STALL) { 426 usb2_transfer_start(sc->sc_xfer[3]); 427 } else { 428 xfer->frlengths[0] = xfer->max_data_length; 429 usb2_start_hardware(xfer); 430 } 431 return; 432 433 default: /* Error */ 434 if (xfer->error != USB_ERR_CANCELLED) { 435 sc->sc_flag |= UVSCOM_FLAG_READ_STALL; 436 usb2_transfer_start(sc->sc_xfer[3]); 437 } 438 return; 439 440 } 441} 442 443static void 444uvscom_read_clear_stall_callback(struct usb2_xfer *xfer) 445{ 446 struct uvscom_softc *sc = xfer->priv_sc; 447 struct usb2_xfer *xfer_other = sc->sc_xfer[1]; 448 449 if (usb2_clear_stall_callback(xfer, xfer_other)) { 450 DPRINTF("stall cleared\n"); 451 sc->sc_flag &= ~UVSCOM_FLAG_READ_STALL; 452 usb2_transfer_start(xfer_other); 453 } 454} 455 456static void 457uvscom_intr_callback(struct usb2_xfer *xfer) 458{ 459 struct uvscom_softc *sc = xfer->priv_sc; 460 uint8_t buf[2]; 461 462 switch (USB_GET_STATE(xfer)) { 463 case USB_ST_TRANSFERRED: 464 if (xfer->actlen >= 2) { 465 466 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf)); 467 468 sc->sc_lsr = 0; 469 sc->sc_msr = 0; 470 sc->sc_unit_status = buf[1]; 471 472 if (buf[0] & UVSCOM_TXRDY) { 473 sc->sc_lsr |= ULSR_TXRDY; 474 } 475 if (buf[0] & UVSCOM_RXRDY) { 476 sc->sc_lsr |= ULSR_RXRDY; 477 } 478 if (buf[1] & UVSCOM_CTS) { 479 sc->sc_msr |= SER_CTS; 480 } 481 if (buf[1] & UVSCOM_DSR) { 482 sc->sc_msr |= SER_DSR; 483 } 484 if (buf[1] & UVSCOM_DCD) { 485 sc->sc_msr |= SER_DCD; 486 } 487 /* 488 * the UCOM layer will ignore this call if the TTY 489 * device is closed! 490 */ 491 usb2_com_status_change(&sc->sc_ucom); 492 } 493 case USB_ST_SETUP: 494 if (sc->sc_flag & UVSCOM_FLAG_INTR_STALL) { 495 usb2_transfer_start(sc->sc_xfer[5]); 496 } else { 497 xfer->frlengths[0] = xfer->max_data_length; 498 usb2_start_hardware(xfer); 499 } 500 return; 501 502 default: /* Error */ 503 if (xfer->error != USB_ERR_CANCELLED) { 504 sc->sc_flag |= UVSCOM_FLAG_INTR_STALL; 505 usb2_transfer_start(sc->sc_xfer[5]); 506 } 507 return; 508 509 } 510} 511 512static void 513uvscom_intr_clear_stall_callback(struct usb2_xfer *xfer) 514{ 515 struct uvscom_softc *sc = xfer->priv_sc; 516 struct usb2_xfer *xfer_other = sc->sc_xfer[4]; 517 518 if (usb2_clear_stall_callback(xfer, xfer_other)) { 519 DPRINTF("stall cleared\n"); 520 sc->sc_flag &= ~UVSCOM_FLAG_INTR_STALL; 521 usb2_transfer_start(xfer_other); 522 } 523} 524 525static void 526uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 527{ 528 struct uvscom_softc *sc = ucom->sc_parent; 529 530 DPRINTF("onoff = %d\n", onoff); 531 532 if (onoff) 533 sc->sc_line |= UVSCOM_DTR; 534 else 535 sc->sc_line &= ~UVSCOM_DTR; 536 537 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 538} 539 540static void 541uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 542{ 543 struct uvscom_softc *sc = ucom->sc_parent; 544 545 DPRINTF("onoff = %d\n", onoff); 546 547 if (onoff) 548 sc->sc_line |= UVSCOM_RTS; 549 else 550 sc->sc_line &= ~UVSCOM_RTS; 551 552 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 553} 554 555static void 556uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 557{ 558 struct uvscom_softc *sc = ucom->sc_parent; 559 560 DPRINTF("onoff = %d\n", onoff); 561 562 if (onoff) 563 sc->sc_line |= UVSCOM_BREAK; 564 else 565 sc->sc_line &= ~UVSCOM_BREAK; 566 567 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line); 568} 569 570static int 571uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 572{ 573 switch (t->c_ospeed) { 574 case B150: 575 case B300: 576 case B600: 577 case B1200: 578 case B2400: 579 case B4800: 580 case B9600: 581 case B19200: 582 case B38400: 583 case B57600: 584 case B115200: 585 default: 586 return (EINVAL); 587 } 588 return (0); 589} 590 591static void 592uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 593{ 594 struct uvscom_softc *sc = ucom->sc_parent; 595 uint16_t value; 596 597 DPRINTF("\n"); 598 599 switch (t->c_ospeed) { 600 case B150: 601 value = UVSCOM_SPEED_150BPS; 602 break; 603 case B300: 604 value = UVSCOM_SPEED_300BPS; 605 break; 606 case B600: 607 value = UVSCOM_SPEED_600BPS; 608 break; 609 case B1200: 610 value = UVSCOM_SPEED_1200BPS; 611 break; 612 case B2400: 613 value = UVSCOM_SPEED_2400BPS; 614 break; 615 case B4800: 616 value = UVSCOM_SPEED_4800BPS; 617 break; 618 case B9600: 619 value = UVSCOM_SPEED_9600BPS; 620 break; 621 case B19200: 622 value = UVSCOM_SPEED_19200BPS; 623 break; 624 case B38400: 625 value = UVSCOM_SPEED_38400BPS; 626 break; 627 case B57600: 628 value = UVSCOM_SPEED_57600BPS; 629 break; 630 case B115200: 631 value = UVSCOM_SPEED_115200BPS; 632 break; 633 default: 634 return; 635 } 636 637 uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value); 638 639 value = 0; 640 641 if (t->c_cflag & CSTOPB) { 642 value |= UVSCOM_STOP_BIT_2; 643 } 644 if (t->c_cflag & PARENB) { 645 if (t->c_cflag & PARODD) { 646 value |= UVSCOM_PARITY_ODD; 647 } else { 648 value |= UVSCOM_PARITY_EVEN; 649 } 650 } else { 651 value |= UVSCOM_PARITY_NONE; 652 } 653 654 switch (t->c_cflag & CSIZE) { 655 case CS5: 656 value |= UVSCOM_DATA_BIT_5; 657 break; 658 case CS6: 659 value |= UVSCOM_DATA_BIT_6; 660 break; 661 case CS7: 662 value |= UVSCOM_DATA_BIT_7; 663 break; 664 default: 665 case CS8: 666 value |= UVSCOM_DATA_BIT_8; 667 break; 668 } 669 670 uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value); 671} 672 673static int 674uvscom_pre_open(struct usb2_com_softc *ucom) 675{ 676 struct uvscom_softc *sc = ucom->sc_parent; 677 678 DPRINTF("sc = %p\n", sc); 679 680 /* check if PC card was inserted */ 681 682 if (sc->sc_unit_status & UVSCOM_NOCARD) { 683 DPRINTF("no PC card!\n"); 684 return (ENXIO); 685 } 686 return (0); 687} 688 689static void 690uvscom_cfg_open(struct usb2_com_softc *ucom) 691{ 692 struct uvscom_softc *sc = ucom->sc_parent; 693 694 DPRINTF("sc = %p\n", sc); 695 696 uvscom_cfg_read_status(sc); 697} 698 699static void 700uvscom_cfg_close(struct usb2_com_softc *ucom) 701{ 702 struct uvscom_softc *sc = ucom->sc_parent; 703 704 DPRINTF("sc=%p\n", sc); 705 706 uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0); 707} 708 709static void 710uvscom_start_read(struct usb2_com_softc *ucom) 711{ 712 struct uvscom_softc *sc = ucom->sc_parent; 713 714 usb2_transfer_start(sc->sc_xfer[1]); 715} 716 717static void 718uvscom_stop_read(struct usb2_com_softc *ucom) 719{ 720 struct uvscom_softc *sc = ucom->sc_parent; 721 722 usb2_transfer_stop(sc->sc_xfer[3]); 723 usb2_transfer_stop(sc->sc_xfer[1]); 724} 725 726static void 727uvscom_start_write(struct usb2_com_softc *ucom) 728{ 729 struct uvscom_softc *sc = ucom->sc_parent; 730 731 usb2_transfer_start(sc->sc_xfer[0]); 732} 733 734static void 735uvscom_stop_write(struct usb2_com_softc *ucom) 736{ 737 struct uvscom_softc *sc = ucom->sc_parent; 738 739 usb2_transfer_stop(sc->sc_xfer[2]); 740 usb2_transfer_stop(sc->sc_xfer[0]); 741} 742 743static void 744uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 745{ 746 struct uvscom_softc *sc = ucom->sc_parent; 747 748 *lsr = sc->sc_lsr; 749 *msr = sc->sc_msr; 750} 751 752static void 753uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value) 754{ 755 struct usb2_device_request req; 756 usb2_error_t err; 757 758 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 759 return; 760 } 761 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 762 req.bRequest = index; 763 USETW(req.wValue, value); 764 USETW(req.wIndex, 0); 765 USETW(req.wLength, 0); 766 767 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 768 NULL, 0, NULL, 1000); 769 if (err) { 770 DPRINTFN(0, "device request failed, err=%s " 771 "(ignored)\n", usb2_errstr(err)); 772 } 773} 774 775static uint16_t 776uvscom_cfg_read_status(struct uvscom_softc *sc) 777{ 778 struct usb2_device_request req; 779 usb2_error_t err; 780 uint8_t data[2]; 781 782 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 783 return (0); 784 } 785 req.bmRequestType = UT_READ_VENDOR_DEVICE; 786 req.bRequest = UVSCOM_READ_STATUS; 787 USETW(req.wValue, 0); 788 USETW(req.wIndex, 0); 789 USETW(req.wLength, 2); 790 791 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req, 792 data, 0, NULL, 1000); 793 if (err) { 794 DPRINTFN(0, "device request failed, err=%s " 795 "(ignored)\n", usb2_errstr(err)); 796 data[0] = 0; 797 data[1] = 0; 798 } 799 return (data[0] | (data[1] << 8)); 800}
|