96 &uchcom_debug, 0, "uchcom debug level"); 97#endif 98 99#define UCHCOM_IFACE_INDEX 0 100#define UCHCOM_CONFIG_INDEX 0 101 102#define UCHCOM_REV_CH340 0x0250 103#define UCHCOM_INPUT_BUF_SIZE 8 104 105#define UCHCOM_REQ_GET_VERSION 0x5F 106#define UCHCOM_REQ_READ_REG 0x95 107#define UCHCOM_REQ_WRITE_REG 0x9A 108#define UCHCOM_REQ_RESET 0xA1 109#define UCHCOM_REQ_SET_DTRRTS 0xA4 110 111#define UCHCOM_REG_STAT1 0x06 112#define UCHCOM_REG_STAT2 0x07 113#define UCHCOM_REG_BPS_PRE 0x12 114#define UCHCOM_REG_BPS_DIV 0x13 115#define UCHCOM_REG_BPS_MOD 0x14 116#define UCHCOM_REG_BPS_PAD 0x0F 117#define UCHCOM_REG_BREAK1 0x05 118#define UCHCOM_REG_BREAK2 0x18 119#define UCHCOM_REG_LCR1 0x18 120#define UCHCOM_REG_LCR2 0x25 121 122#define UCHCOM_VER_20 0x20 123 124#define UCHCOM_BASE_UNKNOWN 0 125#define UCHCOM_BPS_MOD_BASE 20000000 126#define UCHCOM_BPS_MOD_BASE_OFS 1100 127 128#define UCHCOM_DTR_MASK 0x20 129#define UCHCOM_RTS_MASK 0x40 130 131#define UCHCOM_BRK1_MASK 0x01 132#define UCHCOM_BRK2_MASK 0x40 133 134#define UCHCOM_LCR1_MASK 0xAF 135#define UCHCOM_LCR2_MASK 0x07 136#define UCHCOM_LCR1_PARENB 0x80 137#define UCHCOM_LCR2_PAREVEN 0x07 138#define UCHCOM_LCR2_PARODD 0x06 139#define UCHCOM_LCR2_PARMARK 0x05 140#define UCHCOM_LCR2_PARSPACE 0x04 141 142#define UCHCOM_INTR_STAT1 0x02 143#define UCHCOM_INTR_STAT2 0x03 144#define UCHCOM_INTR_LEAST 4 145 146#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */ 147 148enum { 149 UCHCOM_BULK_DT_WR, 150 UCHCOM_BULK_DT_RD, 151 UCHCOM_INTR_DT_RD, 152 UCHCOM_N_TRANSFER, 153}; 154 155struct uchcom_softc { 156 struct usb2_com_super_softc sc_super_ucom; 157 struct usb2_com_softc sc_ucom; 158 159 struct usb2_xfer *sc_xfer[UCHCOM_N_TRANSFER]; 160 struct usb2_device *sc_udev; 161 struct mtx sc_mtx; 162 163 uint8_t sc_dtr; /* local copy */ 164 uint8_t sc_rts; /* local copy */ 165 uint8_t sc_version; 166 uint8_t sc_msr; 167 uint8_t sc_lsr; /* local status register */ 168}; 169 170struct uchcom_divider { 171 uint8_t dv_prescaler; 172 uint8_t dv_div; 173 uint8_t dv_mod; 174}; 175 176struct uchcom_divider_record { 177 uint32_t dvr_high; 178 uint32_t dvr_low; 179 uint32_t dvr_base_clock; 180 struct uchcom_divider dvr_divider; 181}; 182 183static const struct uchcom_divider_record dividers[] = 184{ 185 {307200, 307200, UCHCOM_BASE_UNKNOWN, {7, 0xD9, 0}}, 186 {921600, 921600, UCHCOM_BASE_UNKNOWN, {7, 0xF3, 0}}, 187 {2999999, 23530, 6000000, {3, 0, 0}}, 188 {23529, 2942, 750000, {2, 0, 0}}, 189 {2941, 368, 93750, {1, 0, 0}}, 190 {367, 1, 11719, {0, 0, 0}}, 191}; 192 193#define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0])) 194 195static const struct usb2_device_id uchcom_devs[] = { 196 {USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)}, 197}; 198 199/* protypes */ 200 201static int uchcom_pre_param(struct usb2_com_softc *, struct termios *); 202static void uchcom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 203 uint8_t *); 204static void uchcom_cfg_param(struct usb2_com_softc *, struct termios *); 205static void uchcom_cfg_set_break(struct usb2_com_softc *, uint8_t); 206static void uchcom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 207static void uchcom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 208static void uchcom_start_read(struct usb2_com_softc *); 209static void uchcom_start_write(struct usb2_com_softc *); 210static void uchcom_stop_read(struct usb2_com_softc *); 211static void uchcom_stop_write(struct usb2_com_softc *); 212static void uchcom_update_version(struct uchcom_softc *); 213static void uchcom_convert_status(struct uchcom_softc *, uint8_t); 214static void uchcom_update_status(struct uchcom_softc *); 215static void uchcom_set_dtrrts(struct uchcom_softc *); 216static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t); 217static void uchcom_set_dte_rate(struct uchcom_softc *, uint32_t); 218static void uchcom_set_line_control(struct uchcom_softc *, tcflag_t); 219static void uchcom_clear_chip(struct uchcom_softc *); 220static void uchcom_reset_chip(struct uchcom_softc *); 221 222static device_probe_t uchcom_probe; 223static device_attach_t uchcom_attach; 224static device_detach_t uchcom_detach; 225 226static usb2_callback_t uchcom_intr_callback; 227static usb2_callback_t uchcom_write_callback; 228static usb2_callback_t uchcom_read_callback; 229 230static const struct usb2_config uchcom_config_data[UCHCOM_N_TRANSFER] = { 231 232 [UCHCOM_BULK_DT_WR] = { 233 .type = UE_BULK, 234 .endpoint = UE_ADDR_ANY, 235 .direction = UE_DIR_OUT, 236 .bufsize = UCHCOM_BULK_BUF_SIZE, 237 .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 238 .callback = &uchcom_write_callback, 239 }, 240 241 [UCHCOM_BULK_DT_RD] = { 242 .type = UE_BULK, 243 .endpoint = UE_ADDR_ANY, 244 .direction = UE_DIR_IN, 245 .bufsize = UCHCOM_BULK_BUF_SIZE, 246 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 247 .callback = &uchcom_read_callback, 248 }, 249 250 [UCHCOM_INTR_DT_RD] = { 251 .type = UE_INTERRUPT, 252 .endpoint = UE_ADDR_ANY, 253 .direction = UE_DIR_IN, 254 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 255 .bufsize = 0, /* use wMaxPacketSize */ 256 .callback = &uchcom_intr_callback, 257 }, 258}; 259 260struct usb2_com_callback uchcom_callback = { 261 .usb2_com_cfg_get_status = &uchcom_cfg_get_status, 262 .usb2_com_cfg_set_dtr = &uchcom_cfg_set_dtr, 263 .usb2_com_cfg_set_rts = &uchcom_cfg_set_rts, 264 .usb2_com_cfg_set_break = &uchcom_cfg_set_break, 265 .usb2_com_cfg_param = &uchcom_cfg_param, 266 .usb2_com_pre_param = &uchcom_pre_param, 267 .usb2_com_start_read = &uchcom_start_read, 268 .usb2_com_stop_read = &uchcom_stop_read, 269 .usb2_com_start_write = &uchcom_start_write, 270 .usb2_com_stop_write = &uchcom_stop_write, 271}; 272 273/* ---------------------------------------------------------------------- 274 * driver entry points 275 */ 276 277static int 278uchcom_probe(device_t dev) 279{ 280 struct usb2_attach_arg *uaa = device_get_ivars(dev); 281 282 DPRINTFN(11, "\n"); 283 284 if (uaa->usb_mode != USB_MODE_HOST) { 285 return (ENXIO); 286 } 287 if (uaa->info.bConfigIndex != UCHCOM_CONFIG_INDEX) { 288 return (ENXIO); 289 } 290 if (uaa->info.bIfaceIndex != UCHCOM_IFACE_INDEX) { 291 return (ENXIO); 292 } 293 return (usb2_lookup_id_by_uaa(uchcom_devs, sizeof(uchcom_devs), uaa)); 294} 295 296static int 297uchcom_attach(device_t dev) 298{ 299 struct uchcom_softc *sc = device_get_softc(dev); 300 struct usb2_attach_arg *uaa = device_get_ivars(dev); 301 int error; 302 uint8_t iface_index; 303 304 DPRINTFN(11, "\n"); 305 306 device_set_usb2_desc(dev); 307 mtx_init(&sc->sc_mtx, "uchcom", NULL, MTX_DEF); 308 309 sc->sc_udev = uaa->device; 310 311 switch (uaa->info.bcdDevice) { 312 case UCHCOM_REV_CH340: 313 device_printf(dev, "CH340 detected\n"); 314 break; 315 default: 316 device_printf(dev, "CH341 detected\n"); 317 break; 318 } 319 320 iface_index = UCHCOM_IFACE_INDEX; 321 error = usb2_transfer_setup(uaa->device, 322 &iface_index, sc->sc_xfer, uchcom_config_data, 323 UCHCOM_N_TRANSFER, sc, &sc->sc_mtx); 324 325 if (error) { 326 DPRINTF("one or more missing USB endpoints, " 327 "error=%s\n", usb2_errstr(error)); 328 goto detach; 329 } 330 /* 331 * Do the initialization during attach so that the system does not 332 * sleep during open: 333 */ 334 uchcom_update_version(sc); 335 uchcom_clear_chip(sc); 336 uchcom_reset_chip(sc); 337 uchcom_update_status(sc); 338 339 sc->sc_dtr = 1; 340 sc->sc_rts = 1; 341 342 /* clear stall at first run */ 343 mtx_lock(&sc->sc_mtx); 344 usb2_transfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 345 usb2_transfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 346 mtx_unlock(&sc->sc_mtx); 347 348 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 349 &uchcom_callback, &sc->sc_mtx); 350 if (error) { 351 goto detach; 352 } 353 return (0); 354 355detach: 356 uchcom_detach(dev); 357 return (ENXIO); 358} 359 360static int 361uchcom_detach(device_t dev) 362{ 363 struct uchcom_softc *sc = device_get_softc(dev); 364 365 DPRINTFN(11, "\n"); 366 367 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 368 usb2_transfer_unsetup(sc->sc_xfer, UCHCOM_N_TRANSFER); 369 mtx_destroy(&sc->sc_mtx); 370 371 return (0); 372} 373 374/* ---------------------------------------------------------------------- 375 * low level i/o 376 */ 377 378static void 379uchcom_ctrl_write(struct uchcom_softc *sc, uint8_t reqno, 380 uint16_t value, uint16_t index) 381{ 382 struct usb2_device_request req; 383 384 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 385 req.bRequest = reqno; 386 USETW(req.wValue, value); 387 USETW(req.wIndex, index); 388 USETW(req.wLength, 0); 389 390 usb2_com_cfg_do_request(sc->sc_udev, 391 &sc->sc_ucom, &req, NULL, 0, 1000); 392} 393 394static void 395uchcom_ctrl_read(struct uchcom_softc *sc, uint8_t reqno, 396 uint16_t value, uint16_t index, void *buf, uint16_t buflen) 397{ 398 struct usb2_device_request req; 399 400 req.bmRequestType = UT_READ_VENDOR_DEVICE; 401 req.bRequest = reqno; 402 USETW(req.wValue, value); 403 USETW(req.wIndex, index); 404 USETW(req.wLength, buflen); 405 406 usb2_com_cfg_do_request(sc->sc_udev, 407 &sc->sc_ucom, &req, buf, USB_SHORT_XFER_OK, 1000); 408} 409 410static void 411uchcom_write_reg(struct uchcom_softc *sc, 412 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2) 413{ 414 DPRINTF("0x%02X<-0x%02X, 0x%02X<-0x%02X\n", 415 (unsigned)reg1, (unsigned)val1, 416 (unsigned)reg2, (unsigned)val2); 417 uchcom_ctrl_write( 418 sc, UCHCOM_REQ_WRITE_REG, 419 reg1 | ((uint16_t)reg2 << 8), val1 | ((uint16_t)val2 << 8)); 420} 421 422static void 423uchcom_read_reg(struct uchcom_softc *sc, 424 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2) 425{ 426 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 427 428 uchcom_ctrl_read( 429 sc, UCHCOM_REQ_READ_REG, 430 reg1 | ((uint16_t)reg2 << 8), 0, buf, sizeof(buf)); 431 432 DPRINTF("0x%02X->0x%02X, 0x%02X->0x%02X\n", 433 (unsigned)reg1, (unsigned)buf[0], 434 (unsigned)reg2, (unsigned)buf[1]); 435 436 if (rval1) 437 *rval1 = buf[0]; 438 if (rval2) 439 *rval2 = buf[1]; 440} 441 442static void 443uchcom_get_version(struct uchcom_softc *sc, uint8_t *rver) 444{ 445 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 446 447 uchcom_ctrl_read( 448 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof(buf)); 449 450 if (rver) 451 *rver = buf[0]; 452} 453 454static void 455uchcom_get_status(struct uchcom_softc *sc, uint8_t *rval) 456{ 457 uchcom_read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, NULL); 458} 459 460static void 461uchcom_set_dtrrts_10(struct uchcom_softc *sc, uint8_t val) 462{ 463 uchcom_write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val); 464} 465 466static void 467uchcom_set_dtrrts_20(struct uchcom_softc *sc, uint8_t val) 468{ 469 uchcom_ctrl_write(sc, UCHCOM_REQ_SET_DTRRTS, val, 0); 470} 471 472 473/* ---------------------------------------------------------------------- 474 * middle layer 475 */ 476 477static void 478uchcom_update_version(struct uchcom_softc *sc) 479{ 480 uchcom_get_version(sc, &sc->sc_version); 481} 482 483static void 484uchcom_convert_status(struct uchcom_softc *sc, uint8_t cur) 485{ 486 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK); 487 sc->sc_rts = !(cur & UCHCOM_RTS_MASK); 488 489 cur = ~cur & 0x0F; 490 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur); 491} 492 493static void 494uchcom_update_status(struct uchcom_softc *sc) 495{ 496 uint8_t cur; 497 498 uchcom_get_status(sc, &cur); 499 uchcom_convert_status(sc, cur); 500} 501 502 503static void 504uchcom_set_dtrrts(struct uchcom_softc *sc) 505{ 506 uint8_t val = 0; 507 508 if (sc->sc_dtr) 509 val |= UCHCOM_DTR_MASK; 510 if (sc->sc_rts) 511 val |= UCHCOM_RTS_MASK; 512 513 if (sc->sc_version < UCHCOM_VER_20) 514 uchcom_set_dtrrts_10(sc, ~val); 515 else 516 uchcom_set_dtrrts_20(sc, ~val); 517} 518 519static void 520uchcom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 521{ 522 struct uchcom_softc *sc = ucom->sc_parent; 523 uint8_t brk1; 524 uint8_t brk2; 525 526 uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2); 527 if (onoff) { 528 /* on - clear bits */ 529 brk1 &= ~UCHCOM_BRK1_MASK; 530 brk2 &= ~UCHCOM_BRK2_MASK; 531 } else { 532 /* off - set bits */ 533 brk1 |= UCHCOM_BRK1_MASK; 534 brk2 |= UCHCOM_BRK2_MASK; 535 } 536 uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2); 537} 538 539static int 540uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) 541{ 542 const struct uchcom_divider_record *rp; 543 uint32_t div; 544 uint32_t rem; 545 uint32_t mod; 546 uint8_t i; 547 548 /* find record */ 549 for (i = 0; i != NUM_DIVIDERS; i++) { 550 if (dividers[i].dvr_high >= rate && 551 dividers[i].dvr_low <= rate) { 552 rp = ÷rs[i]; 553 goto found; 554 } 555 } 556 return (-1); 557 558found: 559 dp->dv_prescaler = rp->dvr_divider.dv_prescaler; 560 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN) 561 dp->dv_div = rp->dvr_divider.dv_div; 562 else { 563 div = rp->dvr_base_clock / rate; 564 rem = rp->dvr_base_clock % rate; 565 if (div == 0 || div >= 0xFF) 566 return (-1); 567 if ((rem << 1) >= rate) 568 div += 1; 569 dp->dv_div = (uint8_t)-div; 570 } 571 572 mod = UCHCOM_BPS_MOD_BASE / rate + UCHCOM_BPS_MOD_BASE_OFS; 573 mod = mod + mod / 2; 574 575 dp->dv_mod = mod / 0x100; 576 577 return (0); 578} 579 580static void 581uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate) 582{ 583 struct uchcom_divider dv; 584 585 if (uchcom_calc_divider_settings(&dv, rate)) 586 return; 587 588 uchcom_write_reg(sc, 589 UCHCOM_REG_BPS_PRE, dv.dv_prescaler, 590 UCHCOM_REG_BPS_DIV, dv.dv_div); 591 uchcom_write_reg(sc, 592 UCHCOM_REG_BPS_MOD, dv.dv_mod, 593 UCHCOM_REG_BPS_PAD, 0); 594} 595 596static void 597uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) 598{ 599 uint8_t lcr1 = 0; 600 uint8_t lcr2 = 0; 601 602 uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 603 604 lcr1 &= ~UCHCOM_LCR1_MASK; 605 lcr2 &= ~UCHCOM_LCR2_MASK; 606 607 /* 608 * XXX: it is difficult to handle the line control appropriately: 609 * - CS8, !CSTOPB and any parity mode seems ok, but 610 * - the chip doesn't have the function to calculate parity 611 * in !CS8 mode. 612 * - it is unclear that the chip supports CS5,6 mode. 613 * - it is unclear how to handle stop bits. 614 */ 615 616 if (cflag & PARENB) { 617 lcr1 |= UCHCOM_LCR1_PARENB; 618 if (cflag & PARODD) 619 lcr2 |= UCHCOM_LCR2_PARODD; 620 else 621 lcr2 |= UCHCOM_LCR2_PAREVEN; 622 } 623 uchcom_write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2, lcr2); 624} 625 626static void 627uchcom_clear_chip(struct uchcom_softc *sc) 628{ 629 DPRINTF("\n"); 630 uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0); 631} 632 633static void 634uchcom_reset_chip(struct uchcom_softc *sc) 635{ 636 uint16_t val; 637 uint16_t idx; 638 uint8_t lcr1; 639 uint8_t lcr2; 640 uint8_t pre; 641 uint8_t div; 642 uint8_t mod; 643 644 uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 645 uchcom_read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV, &div); 646 uchcom_read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD, NULL); 647 648 val = 0; 649 idx = 0; 650 val |= (uint16_t)(lcr1 & 0xF0) << 8; 651 val |= 0x01; 652 val |= (uint16_t)(lcr2 & 0x0F) << 8; 653 val |= 0x02; 654 idx |= pre & 0x07; 655 val |= 0x04; 656 idx |= (uint16_t)div << 8; 657 val |= 0x08; 658 idx |= mod & 0xF8; 659 val |= 0x10; 660 661 DPRINTF("reset v=0x%04X, i=0x%04X\n", val, idx); 662 663 uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, val, idx); 664} 665 666/* ---------------------------------------------------------------------- 667 * methods for ucom 668 */ 669static void 670uchcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 671{ 672 struct uchcom_softc *sc = ucom->sc_parent; 673 674 DPRINTF("\n"); 675 676 *lsr = sc->sc_lsr; 677 *msr = sc->sc_msr; 678} 679 680static void 681uchcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 682{ 683 struct uchcom_softc *sc = ucom->sc_parent; 684 685 DPRINTF("onoff = %d\n", onoff); 686 687 sc->sc_dtr = onoff; 688 uchcom_set_dtrrts(sc); 689} 690 691static void 692uchcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 693{ 694 struct uchcom_softc *sc = ucom->sc_parent; 695 696 DPRINTF("onoff = %d\n", onoff); 697 698 sc->sc_rts = onoff; 699 uchcom_set_dtrrts(sc); 700} 701 702static int 703uchcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 704{ 705 struct uchcom_divider dv; 706 707 switch (t->c_cflag & CSIZE) { 708 case CS5: 709 case CS6: 710 case CS7: 711 return (EIO); 712 default: 713 break; 714 } 715 716 if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) { 717 return (EIO); 718 } 719 return (0); /* success */ 720} 721 722static void 723uchcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 724{ 725 struct uchcom_softc *sc = ucom->sc_parent; 726 727 uchcom_set_line_control(sc, t->c_cflag); 728 uchcom_set_dte_rate(sc, t->c_ospeed); 729} 730 731static void 732uchcom_start_read(struct usb2_com_softc *ucom) 733{ 734 struct uchcom_softc *sc = ucom->sc_parent; 735 736 /* start interrupt endpoint */ 737 usb2_transfer_start(sc->sc_xfer[UCHCOM_INTR_DT_RD]); 738 739 /* start read endpoint */ 740 usb2_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 741} 742 743static void 744uchcom_stop_read(struct usb2_com_softc *ucom) 745{ 746 struct uchcom_softc *sc = ucom->sc_parent; 747 748 /* stop interrupt endpoint */ 749 usb2_transfer_stop(sc->sc_xfer[UCHCOM_INTR_DT_RD]); 750 751 /* stop read endpoint */ 752 usb2_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 753} 754 755static void 756uchcom_start_write(struct usb2_com_softc *ucom) 757{ 758 struct uchcom_softc *sc = ucom->sc_parent; 759 760 usb2_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 761} 762 763static void 764uchcom_stop_write(struct usb2_com_softc *ucom) 765{ 766 struct uchcom_softc *sc = ucom->sc_parent; 767 768 usb2_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 769} 770 771/* ---------------------------------------------------------------------- 772 * callback when the modem status is changed. 773 */ 774static void 775uchcom_intr_callback(struct usb2_xfer *xfer) 776{ 777 struct uchcom_softc *sc = xfer->priv_sc; 778 uint8_t buf[UCHCOM_INTR_LEAST]; 779 780 switch (USB_GET_STATE(xfer)) { 781 case USB_ST_TRANSFERRED: 782 783 DPRINTF("actlen = %u\n", xfer->actlen); 784 785 if (xfer->actlen >= UCHCOM_INTR_LEAST) { 786 usb2_copy_out(xfer->frbuffers, 0, buf, 787 UCHCOM_INTR_LEAST); 788 789 DPRINTF("data = 0x%02X 0x%02X 0x%02X 0x%02X\n", 790 (unsigned)buf[0], (unsigned)buf[1], 791 (unsigned)buf[2], (unsigned)buf[3]); 792 793 uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]); 794 usb2_com_status_change(&sc->sc_ucom); 795 } 796 case USB_ST_SETUP: 797tr_setup: 798 xfer->frlengths[0] = xfer->max_data_length; 799 usb2_start_hardware(xfer); 800 break; 801 802 default: /* Error */ 803 if (xfer->error != USB_ERR_CANCELLED) { 804 /* try to clear stall first */ 805 xfer->flags.stall_pipe = 1; 806 goto tr_setup; 807 } 808 break; 809 } 810} 811 812static void 813uchcom_write_callback(struct usb2_xfer *xfer) 814{ 815 struct uchcom_softc *sc = xfer->priv_sc; 816 uint32_t actlen; 817 818 switch (USB_GET_STATE(xfer)) { 819 case USB_ST_SETUP: 820 case USB_ST_TRANSFERRED: 821tr_setup: 822 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 823 UCHCOM_BULK_BUF_SIZE, &actlen)) { 824 825 DPRINTF("actlen = %d\n", actlen); 826 827 xfer->frlengths[0] = actlen; 828 usb2_start_hardware(xfer); 829 } 830 return; 831 832 default: /* Error */ 833 if (xfer->error != USB_ERR_CANCELLED) { 834 /* try to clear stall first */ 835 xfer->flags.stall_pipe = 1; 836 goto tr_setup; 837 } 838 return; 839 840 } 841} 842 843static void 844uchcom_read_callback(struct usb2_xfer *xfer) 845{ 846 struct uchcom_softc *sc = xfer->priv_sc; 847 848 switch (USB_GET_STATE(xfer)) { 849 case USB_ST_TRANSFERRED: 850 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 851 852 case USB_ST_SETUP: 853tr_setup: 854 xfer->frlengths[0] = xfer->max_data_length; 855 usb2_start_hardware(xfer); 856 return; 857 858 default: /* Error */ 859 if (xfer->error != USB_ERR_CANCELLED) { 860 /* try to clear stall first */ 861 xfer->flags.stall_pipe = 1; 862 goto tr_setup; 863 } 864 return; 865 } 866} 867 868static device_method_t uchcom_methods[] = { 869 /* Device interface */ 870 DEVMETHOD(device_probe, uchcom_probe), 871 DEVMETHOD(device_attach, uchcom_attach), 872 DEVMETHOD(device_detach, uchcom_detach), 873 874 {0, 0} 875}; 876 877static driver_t uchcom_driver = { 878 "ucom", 879 uchcom_methods, 880 sizeof(struct uchcom_softc) 881}; 882 883static devclass_t uchcom_devclass; 884 885DRIVER_MODULE(uchcom, uhub, uchcom_driver, uchcom_devclass, NULL, 0); 886MODULE_DEPEND(uchcom, ucom, 1, 1, 1); 887MODULE_DEPEND(uchcom, usb, 1, 1, 1);
| 96 &uchcom_debug, 0, "uchcom debug level"); 97#endif 98 99#define UCHCOM_IFACE_INDEX 0 100#define UCHCOM_CONFIG_INDEX 0 101 102#define UCHCOM_REV_CH340 0x0250 103#define UCHCOM_INPUT_BUF_SIZE 8 104 105#define UCHCOM_REQ_GET_VERSION 0x5F 106#define UCHCOM_REQ_READ_REG 0x95 107#define UCHCOM_REQ_WRITE_REG 0x9A 108#define UCHCOM_REQ_RESET 0xA1 109#define UCHCOM_REQ_SET_DTRRTS 0xA4 110 111#define UCHCOM_REG_STAT1 0x06 112#define UCHCOM_REG_STAT2 0x07 113#define UCHCOM_REG_BPS_PRE 0x12 114#define UCHCOM_REG_BPS_DIV 0x13 115#define UCHCOM_REG_BPS_MOD 0x14 116#define UCHCOM_REG_BPS_PAD 0x0F 117#define UCHCOM_REG_BREAK1 0x05 118#define UCHCOM_REG_BREAK2 0x18 119#define UCHCOM_REG_LCR1 0x18 120#define UCHCOM_REG_LCR2 0x25 121 122#define UCHCOM_VER_20 0x20 123 124#define UCHCOM_BASE_UNKNOWN 0 125#define UCHCOM_BPS_MOD_BASE 20000000 126#define UCHCOM_BPS_MOD_BASE_OFS 1100 127 128#define UCHCOM_DTR_MASK 0x20 129#define UCHCOM_RTS_MASK 0x40 130 131#define UCHCOM_BRK1_MASK 0x01 132#define UCHCOM_BRK2_MASK 0x40 133 134#define UCHCOM_LCR1_MASK 0xAF 135#define UCHCOM_LCR2_MASK 0x07 136#define UCHCOM_LCR1_PARENB 0x80 137#define UCHCOM_LCR2_PAREVEN 0x07 138#define UCHCOM_LCR2_PARODD 0x06 139#define UCHCOM_LCR2_PARMARK 0x05 140#define UCHCOM_LCR2_PARSPACE 0x04 141 142#define UCHCOM_INTR_STAT1 0x02 143#define UCHCOM_INTR_STAT2 0x03 144#define UCHCOM_INTR_LEAST 4 145 146#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */ 147 148enum { 149 UCHCOM_BULK_DT_WR, 150 UCHCOM_BULK_DT_RD, 151 UCHCOM_INTR_DT_RD, 152 UCHCOM_N_TRANSFER, 153}; 154 155struct uchcom_softc { 156 struct usb2_com_super_softc sc_super_ucom; 157 struct usb2_com_softc sc_ucom; 158 159 struct usb2_xfer *sc_xfer[UCHCOM_N_TRANSFER]; 160 struct usb2_device *sc_udev; 161 struct mtx sc_mtx; 162 163 uint8_t sc_dtr; /* local copy */ 164 uint8_t sc_rts; /* local copy */ 165 uint8_t sc_version; 166 uint8_t sc_msr; 167 uint8_t sc_lsr; /* local status register */ 168}; 169 170struct uchcom_divider { 171 uint8_t dv_prescaler; 172 uint8_t dv_div; 173 uint8_t dv_mod; 174}; 175 176struct uchcom_divider_record { 177 uint32_t dvr_high; 178 uint32_t dvr_low; 179 uint32_t dvr_base_clock; 180 struct uchcom_divider dvr_divider; 181}; 182 183static const struct uchcom_divider_record dividers[] = 184{ 185 {307200, 307200, UCHCOM_BASE_UNKNOWN, {7, 0xD9, 0}}, 186 {921600, 921600, UCHCOM_BASE_UNKNOWN, {7, 0xF3, 0}}, 187 {2999999, 23530, 6000000, {3, 0, 0}}, 188 {23529, 2942, 750000, {2, 0, 0}}, 189 {2941, 368, 93750, {1, 0, 0}}, 190 {367, 1, 11719, {0, 0, 0}}, 191}; 192 193#define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0])) 194 195static const struct usb2_device_id uchcom_devs[] = { 196 {USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)}, 197}; 198 199/* protypes */ 200 201static int uchcom_pre_param(struct usb2_com_softc *, struct termios *); 202static void uchcom_cfg_get_status(struct usb2_com_softc *, uint8_t *, 203 uint8_t *); 204static void uchcom_cfg_param(struct usb2_com_softc *, struct termios *); 205static void uchcom_cfg_set_break(struct usb2_com_softc *, uint8_t); 206static void uchcom_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 207static void uchcom_cfg_set_rts(struct usb2_com_softc *, uint8_t); 208static void uchcom_start_read(struct usb2_com_softc *); 209static void uchcom_start_write(struct usb2_com_softc *); 210static void uchcom_stop_read(struct usb2_com_softc *); 211static void uchcom_stop_write(struct usb2_com_softc *); 212static void uchcom_update_version(struct uchcom_softc *); 213static void uchcom_convert_status(struct uchcom_softc *, uint8_t); 214static void uchcom_update_status(struct uchcom_softc *); 215static void uchcom_set_dtrrts(struct uchcom_softc *); 216static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t); 217static void uchcom_set_dte_rate(struct uchcom_softc *, uint32_t); 218static void uchcom_set_line_control(struct uchcom_softc *, tcflag_t); 219static void uchcom_clear_chip(struct uchcom_softc *); 220static void uchcom_reset_chip(struct uchcom_softc *); 221 222static device_probe_t uchcom_probe; 223static device_attach_t uchcom_attach; 224static device_detach_t uchcom_detach; 225 226static usb2_callback_t uchcom_intr_callback; 227static usb2_callback_t uchcom_write_callback; 228static usb2_callback_t uchcom_read_callback; 229 230static const struct usb2_config uchcom_config_data[UCHCOM_N_TRANSFER] = { 231 232 [UCHCOM_BULK_DT_WR] = { 233 .type = UE_BULK, 234 .endpoint = UE_ADDR_ANY, 235 .direction = UE_DIR_OUT, 236 .bufsize = UCHCOM_BULK_BUF_SIZE, 237 .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 238 .callback = &uchcom_write_callback, 239 }, 240 241 [UCHCOM_BULK_DT_RD] = { 242 .type = UE_BULK, 243 .endpoint = UE_ADDR_ANY, 244 .direction = UE_DIR_IN, 245 .bufsize = UCHCOM_BULK_BUF_SIZE, 246 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 247 .callback = &uchcom_read_callback, 248 }, 249 250 [UCHCOM_INTR_DT_RD] = { 251 .type = UE_INTERRUPT, 252 .endpoint = UE_ADDR_ANY, 253 .direction = UE_DIR_IN, 254 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 255 .bufsize = 0, /* use wMaxPacketSize */ 256 .callback = &uchcom_intr_callback, 257 }, 258}; 259 260struct usb2_com_callback uchcom_callback = { 261 .usb2_com_cfg_get_status = &uchcom_cfg_get_status, 262 .usb2_com_cfg_set_dtr = &uchcom_cfg_set_dtr, 263 .usb2_com_cfg_set_rts = &uchcom_cfg_set_rts, 264 .usb2_com_cfg_set_break = &uchcom_cfg_set_break, 265 .usb2_com_cfg_param = &uchcom_cfg_param, 266 .usb2_com_pre_param = &uchcom_pre_param, 267 .usb2_com_start_read = &uchcom_start_read, 268 .usb2_com_stop_read = &uchcom_stop_read, 269 .usb2_com_start_write = &uchcom_start_write, 270 .usb2_com_stop_write = &uchcom_stop_write, 271}; 272 273/* ---------------------------------------------------------------------- 274 * driver entry points 275 */ 276 277static int 278uchcom_probe(device_t dev) 279{ 280 struct usb2_attach_arg *uaa = device_get_ivars(dev); 281 282 DPRINTFN(11, "\n"); 283 284 if (uaa->usb_mode != USB_MODE_HOST) { 285 return (ENXIO); 286 } 287 if (uaa->info.bConfigIndex != UCHCOM_CONFIG_INDEX) { 288 return (ENXIO); 289 } 290 if (uaa->info.bIfaceIndex != UCHCOM_IFACE_INDEX) { 291 return (ENXIO); 292 } 293 return (usb2_lookup_id_by_uaa(uchcom_devs, sizeof(uchcom_devs), uaa)); 294} 295 296static int 297uchcom_attach(device_t dev) 298{ 299 struct uchcom_softc *sc = device_get_softc(dev); 300 struct usb2_attach_arg *uaa = device_get_ivars(dev); 301 int error; 302 uint8_t iface_index; 303 304 DPRINTFN(11, "\n"); 305 306 device_set_usb2_desc(dev); 307 mtx_init(&sc->sc_mtx, "uchcom", NULL, MTX_DEF); 308 309 sc->sc_udev = uaa->device; 310 311 switch (uaa->info.bcdDevice) { 312 case UCHCOM_REV_CH340: 313 device_printf(dev, "CH340 detected\n"); 314 break; 315 default: 316 device_printf(dev, "CH341 detected\n"); 317 break; 318 } 319 320 iface_index = UCHCOM_IFACE_INDEX; 321 error = usb2_transfer_setup(uaa->device, 322 &iface_index, sc->sc_xfer, uchcom_config_data, 323 UCHCOM_N_TRANSFER, sc, &sc->sc_mtx); 324 325 if (error) { 326 DPRINTF("one or more missing USB endpoints, " 327 "error=%s\n", usb2_errstr(error)); 328 goto detach; 329 } 330 /* 331 * Do the initialization during attach so that the system does not 332 * sleep during open: 333 */ 334 uchcom_update_version(sc); 335 uchcom_clear_chip(sc); 336 uchcom_reset_chip(sc); 337 uchcom_update_status(sc); 338 339 sc->sc_dtr = 1; 340 sc->sc_rts = 1; 341 342 /* clear stall at first run */ 343 mtx_lock(&sc->sc_mtx); 344 usb2_transfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 345 usb2_transfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 346 mtx_unlock(&sc->sc_mtx); 347 348 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 349 &uchcom_callback, &sc->sc_mtx); 350 if (error) { 351 goto detach; 352 } 353 return (0); 354 355detach: 356 uchcom_detach(dev); 357 return (ENXIO); 358} 359 360static int 361uchcom_detach(device_t dev) 362{ 363 struct uchcom_softc *sc = device_get_softc(dev); 364 365 DPRINTFN(11, "\n"); 366 367 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 368 usb2_transfer_unsetup(sc->sc_xfer, UCHCOM_N_TRANSFER); 369 mtx_destroy(&sc->sc_mtx); 370 371 return (0); 372} 373 374/* ---------------------------------------------------------------------- 375 * low level i/o 376 */ 377 378static void 379uchcom_ctrl_write(struct uchcom_softc *sc, uint8_t reqno, 380 uint16_t value, uint16_t index) 381{ 382 struct usb2_device_request req; 383 384 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 385 req.bRequest = reqno; 386 USETW(req.wValue, value); 387 USETW(req.wIndex, index); 388 USETW(req.wLength, 0); 389 390 usb2_com_cfg_do_request(sc->sc_udev, 391 &sc->sc_ucom, &req, NULL, 0, 1000); 392} 393 394static void 395uchcom_ctrl_read(struct uchcom_softc *sc, uint8_t reqno, 396 uint16_t value, uint16_t index, void *buf, uint16_t buflen) 397{ 398 struct usb2_device_request req; 399 400 req.bmRequestType = UT_READ_VENDOR_DEVICE; 401 req.bRequest = reqno; 402 USETW(req.wValue, value); 403 USETW(req.wIndex, index); 404 USETW(req.wLength, buflen); 405 406 usb2_com_cfg_do_request(sc->sc_udev, 407 &sc->sc_ucom, &req, buf, USB_SHORT_XFER_OK, 1000); 408} 409 410static void 411uchcom_write_reg(struct uchcom_softc *sc, 412 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2) 413{ 414 DPRINTF("0x%02X<-0x%02X, 0x%02X<-0x%02X\n", 415 (unsigned)reg1, (unsigned)val1, 416 (unsigned)reg2, (unsigned)val2); 417 uchcom_ctrl_write( 418 sc, UCHCOM_REQ_WRITE_REG, 419 reg1 | ((uint16_t)reg2 << 8), val1 | ((uint16_t)val2 << 8)); 420} 421 422static void 423uchcom_read_reg(struct uchcom_softc *sc, 424 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2) 425{ 426 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 427 428 uchcom_ctrl_read( 429 sc, UCHCOM_REQ_READ_REG, 430 reg1 | ((uint16_t)reg2 << 8), 0, buf, sizeof(buf)); 431 432 DPRINTF("0x%02X->0x%02X, 0x%02X->0x%02X\n", 433 (unsigned)reg1, (unsigned)buf[0], 434 (unsigned)reg2, (unsigned)buf[1]); 435 436 if (rval1) 437 *rval1 = buf[0]; 438 if (rval2) 439 *rval2 = buf[1]; 440} 441 442static void 443uchcom_get_version(struct uchcom_softc *sc, uint8_t *rver) 444{ 445 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 446 447 uchcom_ctrl_read( 448 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof(buf)); 449 450 if (rver) 451 *rver = buf[0]; 452} 453 454static void 455uchcom_get_status(struct uchcom_softc *sc, uint8_t *rval) 456{ 457 uchcom_read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, NULL); 458} 459 460static void 461uchcom_set_dtrrts_10(struct uchcom_softc *sc, uint8_t val) 462{ 463 uchcom_write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val); 464} 465 466static void 467uchcom_set_dtrrts_20(struct uchcom_softc *sc, uint8_t val) 468{ 469 uchcom_ctrl_write(sc, UCHCOM_REQ_SET_DTRRTS, val, 0); 470} 471 472 473/* ---------------------------------------------------------------------- 474 * middle layer 475 */ 476 477static void 478uchcom_update_version(struct uchcom_softc *sc) 479{ 480 uchcom_get_version(sc, &sc->sc_version); 481} 482 483static void 484uchcom_convert_status(struct uchcom_softc *sc, uint8_t cur) 485{ 486 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK); 487 sc->sc_rts = !(cur & UCHCOM_RTS_MASK); 488 489 cur = ~cur & 0x0F; 490 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur); 491} 492 493static void 494uchcom_update_status(struct uchcom_softc *sc) 495{ 496 uint8_t cur; 497 498 uchcom_get_status(sc, &cur); 499 uchcom_convert_status(sc, cur); 500} 501 502 503static void 504uchcom_set_dtrrts(struct uchcom_softc *sc) 505{ 506 uint8_t val = 0; 507 508 if (sc->sc_dtr) 509 val |= UCHCOM_DTR_MASK; 510 if (sc->sc_rts) 511 val |= UCHCOM_RTS_MASK; 512 513 if (sc->sc_version < UCHCOM_VER_20) 514 uchcom_set_dtrrts_10(sc, ~val); 515 else 516 uchcom_set_dtrrts_20(sc, ~val); 517} 518 519static void 520uchcom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 521{ 522 struct uchcom_softc *sc = ucom->sc_parent; 523 uint8_t brk1; 524 uint8_t brk2; 525 526 uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2); 527 if (onoff) { 528 /* on - clear bits */ 529 brk1 &= ~UCHCOM_BRK1_MASK; 530 brk2 &= ~UCHCOM_BRK2_MASK; 531 } else { 532 /* off - set bits */ 533 brk1 |= UCHCOM_BRK1_MASK; 534 brk2 |= UCHCOM_BRK2_MASK; 535 } 536 uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2); 537} 538 539static int 540uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) 541{ 542 const struct uchcom_divider_record *rp; 543 uint32_t div; 544 uint32_t rem; 545 uint32_t mod; 546 uint8_t i; 547 548 /* find record */ 549 for (i = 0; i != NUM_DIVIDERS; i++) { 550 if (dividers[i].dvr_high >= rate && 551 dividers[i].dvr_low <= rate) { 552 rp = ÷rs[i]; 553 goto found; 554 } 555 } 556 return (-1); 557 558found: 559 dp->dv_prescaler = rp->dvr_divider.dv_prescaler; 560 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN) 561 dp->dv_div = rp->dvr_divider.dv_div; 562 else { 563 div = rp->dvr_base_clock / rate; 564 rem = rp->dvr_base_clock % rate; 565 if (div == 0 || div >= 0xFF) 566 return (-1); 567 if ((rem << 1) >= rate) 568 div += 1; 569 dp->dv_div = (uint8_t)-div; 570 } 571 572 mod = UCHCOM_BPS_MOD_BASE / rate + UCHCOM_BPS_MOD_BASE_OFS; 573 mod = mod + mod / 2; 574 575 dp->dv_mod = mod / 0x100; 576 577 return (0); 578} 579 580static void 581uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate) 582{ 583 struct uchcom_divider dv; 584 585 if (uchcom_calc_divider_settings(&dv, rate)) 586 return; 587 588 uchcom_write_reg(sc, 589 UCHCOM_REG_BPS_PRE, dv.dv_prescaler, 590 UCHCOM_REG_BPS_DIV, dv.dv_div); 591 uchcom_write_reg(sc, 592 UCHCOM_REG_BPS_MOD, dv.dv_mod, 593 UCHCOM_REG_BPS_PAD, 0); 594} 595 596static void 597uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) 598{ 599 uint8_t lcr1 = 0; 600 uint8_t lcr2 = 0; 601 602 uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 603 604 lcr1 &= ~UCHCOM_LCR1_MASK; 605 lcr2 &= ~UCHCOM_LCR2_MASK; 606 607 /* 608 * XXX: it is difficult to handle the line control appropriately: 609 * - CS8, !CSTOPB and any parity mode seems ok, but 610 * - the chip doesn't have the function to calculate parity 611 * in !CS8 mode. 612 * - it is unclear that the chip supports CS5,6 mode. 613 * - it is unclear how to handle stop bits. 614 */ 615 616 if (cflag & PARENB) { 617 lcr1 |= UCHCOM_LCR1_PARENB; 618 if (cflag & PARODD) 619 lcr2 |= UCHCOM_LCR2_PARODD; 620 else 621 lcr2 |= UCHCOM_LCR2_PAREVEN; 622 } 623 uchcom_write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2, lcr2); 624} 625 626static void 627uchcom_clear_chip(struct uchcom_softc *sc) 628{ 629 DPRINTF("\n"); 630 uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0); 631} 632 633static void 634uchcom_reset_chip(struct uchcom_softc *sc) 635{ 636 uint16_t val; 637 uint16_t idx; 638 uint8_t lcr1; 639 uint8_t lcr2; 640 uint8_t pre; 641 uint8_t div; 642 uint8_t mod; 643 644 uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 645 uchcom_read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV, &div); 646 uchcom_read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD, NULL); 647 648 val = 0; 649 idx = 0; 650 val |= (uint16_t)(lcr1 & 0xF0) << 8; 651 val |= 0x01; 652 val |= (uint16_t)(lcr2 & 0x0F) << 8; 653 val |= 0x02; 654 idx |= pre & 0x07; 655 val |= 0x04; 656 idx |= (uint16_t)div << 8; 657 val |= 0x08; 658 idx |= mod & 0xF8; 659 val |= 0x10; 660 661 DPRINTF("reset v=0x%04X, i=0x%04X\n", val, idx); 662 663 uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, val, idx); 664} 665 666/* ---------------------------------------------------------------------- 667 * methods for ucom 668 */ 669static void 670uchcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 671{ 672 struct uchcom_softc *sc = ucom->sc_parent; 673 674 DPRINTF("\n"); 675 676 *lsr = sc->sc_lsr; 677 *msr = sc->sc_msr; 678} 679 680static void 681uchcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 682{ 683 struct uchcom_softc *sc = ucom->sc_parent; 684 685 DPRINTF("onoff = %d\n", onoff); 686 687 sc->sc_dtr = onoff; 688 uchcom_set_dtrrts(sc); 689} 690 691static void 692uchcom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 693{ 694 struct uchcom_softc *sc = ucom->sc_parent; 695 696 DPRINTF("onoff = %d\n", onoff); 697 698 sc->sc_rts = onoff; 699 uchcom_set_dtrrts(sc); 700} 701 702static int 703uchcom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 704{ 705 struct uchcom_divider dv; 706 707 switch (t->c_cflag & CSIZE) { 708 case CS5: 709 case CS6: 710 case CS7: 711 return (EIO); 712 default: 713 break; 714 } 715 716 if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) { 717 return (EIO); 718 } 719 return (0); /* success */ 720} 721 722static void 723uchcom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 724{ 725 struct uchcom_softc *sc = ucom->sc_parent; 726 727 uchcom_set_line_control(sc, t->c_cflag); 728 uchcom_set_dte_rate(sc, t->c_ospeed); 729} 730 731static void 732uchcom_start_read(struct usb2_com_softc *ucom) 733{ 734 struct uchcom_softc *sc = ucom->sc_parent; 735 736 /* start interrupt endpoint */ 737 usb2_transfer_start(sc->sc_xfer[UCHCOM_INTR_DT_RD]); 738 739 /* start read endpoint */ 740 usb2_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 741} 742 743static void 744uchcom_stop_read(struct usb2_com_softc *ucom) 745{ 746 struct uchcom_softc *sc = ucom->sc_parent; 747 748 /* stop interrupt endpoint */ 749 usb2_transfer_stop(sc->sc_xfer[UCHCOM_INTR_DT_RD]); 750 751 /* stop read endpoint */ 752 usb2_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_RD]); 753} 754 755static void 756uchcom_start_write(struct usb2_com_softc *ucom) 757{ 758 struct uchcom_softc *sc = ucom->sc_parent; 759 760 usb2_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 761} 762 763static void 764uchcom_stop_write(struct usb2_com_softc *ucom) 765{ 766 struct uchcom_softc *sc = ucom->sc_parent; 767 768 usb2_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_WR]); 769} 770 771/* ---------------------------------------------------------------------- 772 * callback when the modem status is changed. 773 */ 774static void 775uchcom_intr_callback(struct usb2_xfer *xfer) 776{ 777 struct uchcom_softc *sc = xfer->priv_sc; 778 uint8_t buf[UCHCOM_INTR_LEAST]; 779 780 switch (USB_GET_STATE(xfer)) { 781 case USB_ST_TRANSFERRED: 782 783 DPRINTF("actlen = %u\n", xfer->actlen); 784 785 if (xfer->actlen >= UCHCOM_INTR_LEAST) { 786 usb2_copy_out(xfer->frbuffers, 0, buf, 787 UCHCOM_INTR_LEAST); 788 789 DPRINTF("data = 0x%02X 0x%02X 0x%02X 0x%02X\n", 790 (unsigned)buf[0], (unsigned)buf[1], 791 (unsigned)buf[2], (unsigned)buf[3]); 792 793 uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]); 794 usb2_com_status_change(&sc->sc_ucom); 795 } 796 case USB_ST_SETUP: 797tr_setup: 798 xfer->frlengths[0] = xfer->max_data_length; 799 usb2_start_hardware(xfer); 800 break; 801 802 default: /* Error */ 803 if (xfer->error != USB_ERR_CANCELLED) { 804 /* try to clear stall first */ 805 xfer->flags.stall_pipe = 1; 806 goto tr_setup; 807 } 808 break; 809 } 810} 811 812static void 813uchcom_write_callback(struct usb2_xfer *xfer) 814{ 815 struct uchcom_softc *sc = xfer->priv_sc; 816 uint32_t actlen; 817 818 switch (USB_GET_STATE(xfer)) { 819 case USB_ST_SETUP: 820 case USB_ST_TRANSFERRED: 821tr_setup: 822 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0, 823 UCHCOM_BULK_BUF_SIZE, &actlen)) { 824 825 DPRINTF("actlen = %d\n", actlen); 826 827 xfer->frlengths[0] = actlen; 828 usb2_start_hardware(xfer); 829 } 830 return; 831 832 default: /* Error */ 833 if (xfer->error != USB_ERR_CANCELLED) { 834 /* try to clear stall first */ 835 xfer->flags.stall_pipe = 1; 836 goto tr_setup; 837 } 838 return; 839 840 } 841} 842 843static void 844uchcom_read_callback(struct usb2_xfer *xfer) 845{ 846 struct uchcom_softc *sc = xfer->priv_sc; 847 848 switch (USB_GET_STATE(xfer)) { 849 case USB_ST_TRANSFERRED: 850 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen); 851 852 case USB_ST_SETUP: 853tr_setup: 854 xfer->frlengths[0] = xfer->max_data_length; 855 usb2_start_hardware(xfer); 856 return; 857 858 default: /* Error */ 859 if (xfer->error != USB_ERR_CANCELLED) { 860 /* try to clear stall first */ 861 xfer->flags.stall_pipe = 1; 862 goto tr_setup; 863 } 864 return; 865 } 866} 867 868static device_method_t uchcom_methods[] = { 869 /* Device interface */ 870 DEVMETHOD(device_probe, uchcom_probe), 871 DEVMETHOD(device_attach, uchcom_attach), 872 DEVMETHOD(device_detach, uchcom_detach), 873 874 {0, 0} 875}; 876 877static driver_t uchcom_driver = { 878 "ucom", 879 uchcom_methods, 880 sizeof(struct uchcom_softc) 881}; 882 883static devclass_t uchcom_devclass; 884 885DRIVER_MODULE(uchcom, uhub, uchcom_driver, uchcom_devclass, NULL, 0); 886MODULE_DEPEND(uchcom, ucom, 1, 1, 1); 887MODULE_DEPEND(uchcom, usb, 1, 1, 1);
|