1 /* $OpenBSD: uchcom.c,v 1.33 2022/04/09 20:07:44 naddy Exp $ */ 2 /* $NetBSD: uchcom.c,v 1.1 2007/09/03 17:57:37 tshiozak Exp $ */ 3 4 /* 5 * Copyright (c) 2007 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Takuya SHIOZAKI (tshiozak@netbsd.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * driver for WinChipHead CH341/340, the worst USB-serial chip in the world. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/tty.h> 42 #include <sys/device.h> 43 44 #include <dev/usb/usb.h> 45 #include <dev/usb/usbdi.h> 46 #include <dev/usb/usbdi_util.h> 47 #include <dev/usb/usbdevs.h> 48 #include <dev/usb/ucomvar.h> 49 50 #ifdef UCHCOM_DEBUG 51 #define DPRINTFN(n, x) do { if (uchcomdebug > (n)) printf x; } while (0) 52 int uchcomdebug = 0; 53 #else 54 #define DPRINTFN(n, x) 55 #endif 56 #define DPRINTF(x) DPRINTFN(0, x) 57 58 #define UCHCOM_IFACE_INDEX 0 59 60 #define UCHCOM_REV_CH340 0x0250 61 #define UCHCOM_INPUT_BUF_SIZE 8 62 63 #define UCHCOM_REQ_GET_VERSION 0x5F 64 #define UCHCOM_REQ_READ_REG 0x95 65 #define UCHCOM_REQ_WRITE_REG 0x9A 66 #define UCHCOM_REQ_RESET 0xA1 67 #define UCHCOM_REQ_SET_DTRRTS 0xA4 68 69 #define UCHCOM_REG_STAT1 0x06 70 #define UCHCOM_REG_STAT2 0x07 71 #define UCHCOM_REG_BPS_PRE 0x12 72 #define UCHCOM_REG_BPS_DIV 0x13 73 #define UCHCOM_REG_BPS_MOD 0x14 74 #define UCHCOM_REG_BPS_PAD 0x0F 75 #define UCHCOM_REG_BREAK 0x05 76 #define UCHCOM_REG_LCR 0x18 77 #define UCHCOM_REG_LCR2 0x25 78 79 #define UCHCOM_VER_20 0x20 80 81 #define UCHCOM_BASE_UNKNOWN 0 82 #define UCHCOM_BPS_MOD_BASE 20000000 83 #define UCHCOM_BPS_MOD_BASE_OFS 1100 84 85 #define UCHCOM_BPS_PRE_IMM 0x80 /* CH341: immediate RX forwarding */ 86 87 #define UCHCOM_DTR_MASK 0x20 88 #define UCHCOM_RTS_MASK 0x40 89 90 #define UCHCOM_BREAK_MASK 0x01 91 92 #define UCHCOM_LCR_CS5 0x00 93 #define UCHCOM_LCR_CS6 0x01 94 #define UCHCOM_LCR_CS7 0x02 95 #define UCHCOM_LCR_CS8 0x03 96 #define UCHCOM_LCR_STOPB 0x04 97 #define UCHCOM_LCR_PARENB 0x08 98 #define UCHCOM_LCR_PARODD 0x00 99 #define UCHCOM_LCR_PAREVEN 0x10 100 #define UCHCOM_LCR_PARMARK 0x20 101 #define UCHCOM_LCR_PARSPACE 0x30 102 #define UCHCOM_LCR_TXE 0x40 103 #define UCHCOM_LCR_RXE 0x80 104 105 #define UCHCOM_INTR_STAT1 0x02 106 #define UCHCOM_INTR_STAT2 0x03 107 #define UCHCOM_INTR_LEAST 4 108 109 /* 110 * XXX - these magic numbers come from Linux (drivers/usb/serial/ch341.c). 111 * The manufacturer was unresponsive when asked for documentation. 112 */ 113 #define UCHCOM_RESET_VALUE 0x501F /* line mode? */ 114 #define UCHCOM_RESET_INDEX 0xD90A /* baud rate? */ 115 116 #define UCHCOMOBUFSIZE 256 117 118 struct uchcom_softc 119 { 120 struct device sc_dev; 121 struct usbd_device *sc_udev; 122 struct device *sc_subdev; 123 struct usbd_interface *sc_iface; 124 /* */ 125 int sc_intr_endpoint; 126 struct usbd_pipe *sc_intr_pipe; 127 u_char *sc_intr_buf; 128 int sc_isize; 129 /* */ 130 int sc_release; 131 uint8_t sc_version; 132 int sc_dtr; 133 int sc_rts; 134 u_char sc_lsr; 135 u_char sc_msr; 136 int sc_lcr1; 137 int sc_lcr2; 138 }; 139 140 struct uchcom_endpoints 141 { 142 int ep_bulkin; 143 int ep_bulkin_size; 144 int ep_bulkout; 145 int ep_intr; 146 int ep_intr_size; 147 }; 148 149 struct uchcom_divider 150 { 151 uint8_t dv_prescaler; 152 uint8_t dv_div; 153 uint8_t dv_mod; 154 }; 155 156 struct uchcom_divider_record 157 { 158 uint32_t dvr_high; 159 uint32_t dvr_low; 160 uint32_t dvr_base_clock; 161 struct uchcom_divider dvr_divider; 162 }; 163 164 static const struct uchcom_divider_record dividers[] = 165 { 166 { 307200, 307200, UCHCOM_BASE_UNKNOWN, { 7, 0xD9, 0 } }, 167 { 921600, 921600, UCHCOM_BASE_UNKNOWN, { 7, 0xF3, 0 } }, 168 { 2999999, 23530, 6000000, { 3, 0, 0 } }, 169 { 23529, 2942, 750000, { 2, 0, 0 } }, 170 { 2941, 368, 93750, { 1, 0, 0 } }, 171 { 367, 1, 11719, { 0, 0, 0 } }, 172 }; 173 174 void uchcom_get_status(void *, int, u_char *, u_char *); 175 void uchcom_set(void *, int, int, int); 176 int uchcom_param(void *, int, struct termios *); 177 int uchcom_open(void *, int); 178 void uchcom_close(void *, int); 179 void uchcom_intr(struct usbd_xfer *, void *, usbd_status); 180 181 int uchcom_find_ifaces(struct uchcom_softc *, 182 struct usbd_interface **); 183 int uchcom_find_endpoints(struct uchcom_softc *, 184 struct uchcom_endpoints *); 185 void uchcom_close_intr_pipe(struct uchcom_softc *); 186 187 188 usbd_status uchcom_generic_control_out(struct uchcom_softc *sc, 189 uint8_t reqno, uint16_t value, uint16_t index); 190 usbd_status uchcom_generic_control_in(struct uchcom_softc *, uint8_t, 191 uint16_t, uint16_t, void *, int, int *); 192 usbd_status uchcom_write_reg(struct uchcom_softc *, uint8_t, uint8_t, 193 uint8_t, uint8_t); 194 usbd_status uchcom_read_reg(struct uchcom_softc *, uint8_t, uint8_t *, 195 uint8_t, uint8_t *); 196 usbd_status uchcom_get_version(struct uchcom_softc *, uint8_t *); 197 usbd_status uchcom_read_status(struct uchcom_softc *, uint8_t *); 198 usbd_status uchcom_set_dtrrts_10(struct uchcom_softc *, uint8_t); 199 usbd_status uchcom_set_dtrrts_20(struct uchcom_softc *, uint8_t); 200 int uchcom_update_version(struct uchcom_softc *); 201 void uchcom_convert_status(struct uchcom_softc *, uint8_t); 202 int uchcom_update_status(struct uchcom_softc *); 203 int uchcom_set_dtrrts(struct uchcom_softc *, int, int); 204 int uchcom_set_break(struct uchcom_softc *, int); 205 int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t); 206 int uchcom_set_dte_rate(struct uchcom_softc *, uint32_t); 207 int uchcom_set_line_control(struct uchcom_softc *, tcflag_t); 208 int uchcom_clear_chip(struct uchcom_softc *); 209 int uchcom_reset_chip(struct uchcom_softc *); 210 int uchcom_setup_comm(struct uchcom_softc *); 211 int uchcom_setup_intr_pipe(struct uchcom_softc *); 212 213 214 int uchcom_match(struct device *, void *, void *); 215 void uchcom_attach(struct device *, struct device *, void *); 216 int uchcom_detach(struct device *, int); 217 218 const struct ucom_methods uchcom_methods = { 219 uchcom_get_status, 220 uchcom_set, 221 uchcom_param, 222 NULL, 223 uchcom_open, 224 uchcom_close, 225 NULL, 226 NULL, 227 }; 228 229 static const struct usb_devno uchcom_devs[] = { 230 { USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341 }, 231 { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH340 }, 232 { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341A } 233 }; 234 235 struct cfdriver uchcom_cd = { 236 NULL, "uchcom", DV_DULL 237 }; 238 239 const struct cfattach uchcom_ca = { 240 sizeof(struct uchcom_softc), uchcom_match, uchcom_attach, uchcom_detach 241 }; 242 243 /* ---------------------------------------------------------------------- 244 * driver entry points 245 */ 246 247 int 248 uchcom_match(struct device *parent, void *match, void *aux) 249 { 250 struct usb_attach_arg *uaa = aux; 251 252 if (uaa->iface == NULL) 253 return UMATCH_NONE; 254 255 return (usb_lookup(uchcom_devs, uaa->vendor, uaa->product) != NULL ? 256 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 257 } 258 259 void 260 uchcom_attach(struct device *parent, struct device *self, void *aux) 261 { 262 struct uchcom_softc *sc = (struct uchcom_softc *)self; 263 struct usb_attach_arg *uaa = aux; 264 struct ucom_attach_args uca; 265 struct usbd_device *dev = uaa->device; 266 struct uchcom_endpoints endpoints; 267 268 sc->sc_udev = dev; 269 sc->sc_dtr = sc->sc_rts = -1; 270 sc->sc_release = uaa->release; 271 272 DPRINTF(("\n\nuchcom attach: sc=%p\n", sc)); 273 274 switch (sc->sc_release) { 275 case UCHCOM_REV_CH340: 276 printf("%s: CH340\n", sc->sc_dev.dv_xname); 277 break; 278 default: 279 printf("%s: CH341\n", sc->sc_dev.dv_xname); 280 break; 281 } 282 283 if (uchcom_find_ifaces(sc, &sc->sc_iface)) 284 goto failed; 285 286 if (uchcom_find_endpoints(sc, &endpoints)) 287 goto failed; 288 289 sc->sc_intr_endpoint = endpoints.ep_intr; 290 sc->sc_isize = endpoints.ep_intr_size; 291 292 /* setup ucom layer */ 293 uca.portno = UCOM_UNK_PORTNO; 294 uca.bulkin = endpoints.ep_bulkin; 295 uca.bulkout = endpoints.ep_bulkout; 296 uca.ibufsize = endpoints.ep_bulkin_size; 297 uca.obufsize = UCHCOMOBUFSIZE; 298 uca.ibufsizepad = endpoints.ep_bulkin_size; 299 uca.opkthdrlen = 0; 300 uca.device = dev; 301 uca.iface = sc->sc_iface; 302 uca.methods = &uchcom_methods; 303 uca.arg = sc; 304 uca.info = NULL; 305 306 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 307 308 return; 309 310 failed: 311 usbd_deactivate(sc->sc_udev); 312 } 313 314 int 315 uchcom_detach(struct device *self, int flags) 316 { 317 struct uchcom_softc *sc = (struct uchcom_softc *)self; 318 int rv = 0; 319 320 DPRINTF(("uchcom_detach: sc=%p flags=%d\n", sc, flags)); 321 322 uchcom_close_intr_pipe(sc); 323 324 if (sc->sc_subdev != NULL) { 325 rv = config_detach(sc->sc_subdev, flags); 326 sc->sc_subdev = NULL; 327 } 328 329 return rv; 330 } 331 332 int 333 uchcom_find_ifaces(struct uchcom_softc *sc, struct usbd_interface **riface) 334 { 335 usbd_status err; 336 337 err = usbd_device2interface_handle(sc->sc_udev, UCHCOM_IFACE_INDEX, 338 riface); 339 if (err) { 340 printf("\n%s: failed to get interface: %s\n", 341 sc->sc_dev.dv_xname, usbd_errstr(err)); 342 return -1; 343 } 344 345 return 0; 346 } 347 348 int 349 uchcom_find_endpoints(struct uchcom_softc *sc, 350 struct uchcom_endpoints *endpoints) 351 { 352 int i, bin=-1, bout=-1, intr=-1, binsize=0, isize=0; 353 usb_interface_descriptor_t *id; 354 usb_endpoint_descriptor_t *ed; 355 356 id = usbd_get_interface_descriptor(sc->sc_iface); 357 358 for (i = 0; i < id->bNumEndpoints; i++) { 359 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 360 if (ed == NULL) { 361 printf("%s: no endpoint descriptor for %d\n", 362 sc->sc_dev.dv_xname, i); 363 return -1; 364 } 365 366 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 367 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 368 intr = ed->bEndpointAddress; 369 isize = UGETW(ed->wMaxPacketSize); 370 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 371 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 372 bin = ed->bEndpointAddress; 373 binsize = UGETW(ed->wMaxPacketSize); 374 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 375 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 376 bout = ed->bEndpointAddress; 377 } 378 } 379 380 if (intr == -1 || bin == -1 || bout == -1) { 381 if (intr == -1) { 382 printf("%s: no interrupt end point\n", 383 sc->sc_dev.dv_xname); 384 } 385 if (bin == -1) { 386 printf("%s: no data bulk in end point\n", 387 sc->sc_dev.dv_xname); 388 } 389 if (bout == -1) { 390 printf("%s: no data bulk out end point\n", 391 sc->sc_dev.dv_xname); 392 } 393 return -1; 394 } 395 if (isize < UCHCOM_INTR_LEAST) { 396 printf("%s: intr pipe is too short", sc->sc_dev.dv_xname); 397 return -1; 398 } 399 400 DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n", 401 sc->sc_dev.dv_xname, bin, bout, intr, isize)); 402 403 endpoints->ep_intr = intr; 404 endpoints->ep_intr_size = isize; 405 endpoints->ep_bulkin = bin; 406 endpoints->ep_bulkin_size = binsize; 407 endpoints->ep_bulkout = bout; 408 409 return 0; 410 } 411 412 413 /* ---------------------------------------------------------------------- 414 * low level i/o 415 */ 416 417 usbd_status 418 uchcom_generic_control_out(struct uchcom_softc *sc, uint8_t reqno, 419 uint16_t value, uint16_t index) 420 { 421 usb_device_request_t req; 422 423 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 424 req.bRequest = reqno; 425 USETW(req.wValue, value); 426 USETW(req.wIndex, index); 427 USETW(req.wLength, 0); 428 429 return usbd_do_request(sc->sc_udev, &req, 0); 430 } 431 432 usbd_status 433 uchcom_generic_control_in(struct uchcom_softc *sc, uint8_t reqno, 434 uint16_t value, uint16_t index, void *buf, int buflen, int *actlen) 435 { 436 usb_device_request_t req; 437 438 req.bmRequestType = UT_READ_VENDOR_DEVICE; 439 req.bRequest = reqno; 440 USETW(req.wValue, value); 441 USETW(req.wIndex, index); 442 USETW(req.wLength, (uint16_t)buflen); 443 444 return usbd_do_request_flags(sc->sc_udev, &req, buf, 445 USBD_SHORT_XFER_OK, actlen, 446 USBD_DEFAULT_TIMEOUT); 447 } 448 449 usbd_status 450 uchcom_write_reg(struct uchcom_softc *sc, 451 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2) 452 { 453 DPRINTF(("uchcom: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n", 454 (unsigned)reg1, (unsigned)val1, 455 (unsigned)reg2, (unsigned)val2)); 456 return uchcom_generic_control_out( 457 sc, UCHCOM_REQ_WRITE_REG, 458 reg1|((uint16_t)reg2<<8), val1|((uint16_t)val2<<8)); 459 } 460 461 usbd_status 462 uchcom_read_reg(struct uchcom_softc *sc, 463 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2) 464 { 465 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 466 usbd_status err; 467 int actin; 468 469 err = uchcom_generic_control_in( 470 sc, UCHCOM_REQ_READ_REG, 471 reg1|((uint16_t)reg2<<8), 0, buf, sizeof buf, &actin); 472 if (err) 473 return err; 474 475 DPRINTF(("uchcom: read reg 0x%02X->0x%02X, 0x%02X->0x%02X\n", 476 (unsigned)reg1, (unsigned)buf[0], 477 (unsigned)reg2, (unsigned)buf[1])); 478 479 if (rval1) *rval1 = buf[0]; 480 if (rval2) *rval2 = buf[1]; 481 482 return USBD_NORMAL_COMPLETION; 483 } 484 485 usbd_status 486 uchcom_get_version(struct uchcom_softc *sc, uint8_t *rver) 487 { 488 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 489 usbd_status err; 490 int actin; 491 492 err = uchcom_generic_control_in( 493 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof buf, &actin); 494 if (err) 495 return err; 496 497 if (rver) *rver = buf[0]; 498 499 return USBD_NORMAL_COMPLETION; 500 } 501 502 usbd_status 503 uchcom_read_status(struct uchcom_softc *sc, uint8_t *rval) 504 { 505 return uchcom_read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, 506 NULL); 507 } 508 509 usbd_status 510 uchcom_set_dtrrts_10(struct uchcom_softc *sc, uint8_t val) 511 { 512 return uchcom_write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, 513 val); 514 } 515 516 usbd_status 517 uchcom_set_dtrrts_20(struct uchcom_softc *sc, uint8_t val) 518 { 519 return uchcom_generic_control_out(sc, UCHCOM_REQ_SET_DTRRTS, val, 0); 520 } 521 522 523 /* ---------------------------------------------------------------------- 524 * middle layer 525 */ 526 527 int 528 uchcom_update_version(struct uchcom_softc *sc) 529 { 530 usbd_status err; 531 532 err = uchcom_get_version(sc, &sc->sc_version); 533 if (err) { 534 printf("%s: cannot get version: %s\n", 535 sc->sc_dev.dv_xname, usbd_errstr(err)); 536 return EIO; 537 } 538 539 return 0; 540 } 541 542 void 543 uchcom_convert_status(struct uchcom_softc *sc, uint8_t cur) 544 { 545 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK); 546 sc->sc_rts = !(cur & UCHCOM_RTS_MASK); 547 548 cur = ~cur & 0x0F; 549 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur); 550 } 551 552 int 553 uchcom_update_status(struct uchcom_softc *sc) 554 { 555 usbd_status err; 556 uint8_t cur; 557 558 err = uchcom_read_status(sc, &cur); 559 if (err) { 560 printf("%s: cannot update status: %s\n", 561 sc->sc_dev.dv_xname, usbd_errstr(err)); 562 return EIO; 563 } 564 uchcom_convert_status(sc, cur); 565 566 return 0; 567 } 568 569 570 int 571 uchcom_set_dtrrts(struct uchcom_softc *sc, int dtr, int rts) 572 { 573 usbd_status err; 574 uint8_t val = 0; 575 576 if (dtr) val |= UCHCOM_DTR_MASK; 577 if (rts) val |= UCHCOM_RTS_MASK; 578 579 if (sc->sc_version < UCHCOM_VER_20) 580 err = uchcom_set_dtrrts_10(sc, ~val); 581 else 582 err = uchcom_set_dtrrts_20(sc, ~val); 583 584 if (err) { 585 printf("%s: cannot set DTR/RTS: %s\n", 586 sc->sc_dev.dv_xname, usbd_errstr(err)); 587 return EIO; 588 } 589 590 return 0; 591 } 592 593 int 594 uchcom_set_break(struct uchcom_softc *sc, int onoff) 595 { 596 usbd_status err; 597 uint8_t brk, lcr; 598 599 err = uchcom_read_reg(sc, UCHCOM_REG_BREAK, &brk, UCHCOM_REG_LCR, &lcr); 600 if (err) 601 return EIO; 602 if (onoff) { 603 /* on - clear bits */ 604 brk &= ~UCHCOM_BREAK_MASK; 605 lcr &= ~UCHCOM_LCR_TXE; 606 } else { 607 /* off - set bits */ 608 brk |= UCHCOM_BREAK_MASK; 609 lcr |= UCHCOM_LCR_TXE; 610 } 611 err = uchcom_write_reg(sc, UCHCOM_REG_BREAK, brk, UCHCOM_REG_LCR, lcr); 612 if (err) 613 return EIO; 614 615 return 0; 616 } 617 618 int 619 uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) 620 { 621 int i; 622 const struct uchcom_divider_record *rp; 623 uint32_t div, rem, mod; 624 625 /* find record */ 626 for (i=0; i<nitems(dividers); i++) { 627 if (dividers[i].dvr_high >= rate && 628 dividers[i].dvr_low <= rate) { 629 rp = ÷rs[i]; 630 goto found; 631 } 632 } 633 return -1; 634 635 found: 636 dp->dv_prescaler = rp->dvr_divider.dv_prescaler; 637 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN) 638 dp->dv_div = rp->dvr_divider.dv_div; 639 else { 640 div = rp->dvr_base_clock / rate; 641 rem = rp->dvr_base_clock % rate; 642 if (div==0 || div>=0xFF) 643 return -1; 644 if ((rem<<1) >= rate) 645 div += 1; 646 dp->dv_div = (uint8_t)-div; 647 } 648 649 mod = UCHCOM_BPS_MOD_BASE/rate + UCHCOM_BPS_MOD_BASE_OFS; 650 mod = mod + mod/2; 651 652 dp->dv_mod = mod / 0x100; 653 654 return 0; 655 } 656 657 int 658 uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate) 659 { 660 usbd_status err; 661 struct uchcom_divider dv; 662 663 if (uchcom_calc_divider_settings(&dv, rate)) 664 return EINVAL; 665 666 if ((err = uchcom_write_reg(sc, 667 UCHCOM_REG_BPS_PRE, dv.dv_prescaler, 668 UCHCOM_REG_BPS_DIV, dv.dv_div)) || 669 (err = uchcom_write_reg(sc, 670 UCHCOM_REG_BPS_MOD, dv.dv_mod, 671 UCHCOM_REG_BPS_PAD, 0))) { 672 printf("%s: cannot set DTE rate: %s\n", 673 sc->sc_dev.dv_xname, usbd_errstr(err)); 674 return EIO; 675 } 676 677 return 0; 678 } 679 680 int 681 uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) 682 { 683 usbd_status err; 684 uint8_t lcr = 0, lcr2 = 0; 685 686 if (sc->sc_release == UCHCOM_REV_CH340) { 687 /* 688 * XXX: it is difficult to handle the line control 689 * appropriately on CH340: 690 * work as chip default - CS8, no parity, !CSTOPB 691 * other modes are not supported. 692 */ 693 switch (ISSET(cflag, CSIZE)) { 694 case CS5: 695 case CS6: 696 case CS7: 697 return EINVAL; 698 case CS8: 699 break; 700 } 701 if (ISSET(cflag, PARENB) || ISSET(cflag, CSTOPB)) 702 return EINVAL; 703 return 0; 704 } 705 706 err = uchcom_read_reg(sc, UCHCOM_REG_LCR, &lcr, 707 UCHCOM_REG_LCR2, &lcr2); 708 if (err) { 709 printf("%s: cannot get LCR: %s\n", 710 sc->sc_dev.dv_xname, usbd_errstr(err)); 711 return EIO; 712 } 713 714 lcr = UCHCOM_LCR_RXE | UCHCOM_LCR_TXE; 715 716 switch (ISSET(cflag, CSIZE)) { 717 case CS5: 718 lcr |= UCHCOM_LCR_CS5; 719 break; 720 case CS6: 721 lcr |= UCHCOM_LCR_CS6; 722 break; 723 case CS7: 724 lcr |= UCHCOM_LCR_CS7; 725 break; 726 case CS8: 727 lcr |= UCHCOM_LCR_CS8; 728 break; 729 } 730 731 if (ISSET(cflag, PARENB)) { 732 lcr |= UCHCOM_LCR_PARENB; 733 if (!ISSET(cflag, PARODD)) 734 lcr |= UCHCOM_LCR_PAREVEN; 735 } 736 737 if (ISSET(cflag, CSTOPB)) { 738 lcr |= UCHCOM_LCR_STOPB; 739 } 740 741 err = uchcom_write_reg(sc, UCHCOM_REG_LCR, lcr, UCHCOM_REG_LCR2, lcr2); 742 if (err) { 743 printf("%s: cannot set LCR: %s\n", 744 sc->sc_dev.dv_xname, usbd_errstr(err)); 745 return EIO; 746 } 747 748 return 0; 749 } 750 751 int 752 uchcom_clear_chip(struct uchcom_softc *sc) 753 { 754 usbd_status err; 755 756 DPRINTF(("%s: clear\n", sc->sc_dev.dv_xname)); 757 err = uchcom_generic_control_out(sc, UCHCOM_REQ_RESET, 0, 0); 758 if (err) { 759 printf("%s: cannot clear: %s\n", 760 sc->sc_dev.dv_xname, usbd_errstr(err)); 761 return EIO; 762 } 763 764 return 0; 765 } 766 767 int 768 uchcom_reset_chip(struct uchcom_softc *sc) 769 { 770 usbd_status err; 771 772 DPRINTF(("%s: reset\n", sc->sc_dev.dv_xname)); 773 774 err = uchcom_generic_control_out(sc, UCHCOM_REQ_RESET, 775 UCHCOM_RESET_VALUE, 776 UCHCOM_RESET_INDEX); 777 if (err) 778 goto failed; 779 780 return 0; 781 782 failed: 783 printf("%s: cannot reset: %s\n", 784 sc->sc_dev.dv_xname, usbd_errstr(err)); 785 return EIO; 786 } 787 788 int 789 uchcom_setup_comm(struct uchcom_softc *sc) 790 { 791 int ret; 792 793 ret = uchcom_update_version(sc); 794 if (ret) 795 return ret; 796 797 ret = uchcom_clear_chip(sc); 798 if (ret) 799 return ret; 800 801 ret = uchcom_set_dte_rate(sc, TTYDEF_SPEED); 802 if (ret) 803 return ret; 804 805 ret = uchcom_set_line_control(sc, CS8); 806 if (ret) 807 return ret; 808 809 ret = uchcom_update_status(sc); 810 if (ret) 811 return ret; 812 813 ret = uchcom_reset_chip(sc); 814 if (ret) 815 return ret; 816 817 ret = uchcom_set_dte_rate(sc, TTYDEF_SPEED); /* XXX */ 818 if (ret) 819 return ret; 820 821 sc->sc_dtr = sc->sc_rts = 1; 822 ret = uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 823 if (ret) 824 return ret; 825 826 return 0; 827 } 828 829 int 830 uchcom_setup_intr_pipe(struct uchcom_softc *sc) 831 { 832 usbd_status err; 833 834 if (sc->sc_intr_endpoint != -1 && sc->sc_intr_pipe == NULL) { 835 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 836 err = usbd_open_pipe_intr(sc->sc_iface, 837 sc->sc_intr_endpoint, 838 USBD_SHORT_XFER_OK, 839 &sc->sc_intr_pipe, sc, 840 sc->sc_intr_buf, 841 sc->sc_isize, 842 uchcom_intr, USBD_DEFAULT_INTERVAL); 843 if (err) { 844 printf("%s: cannot open interrupt pipe: %s\n", 845 sc->sc_dev.dv_xname, 846 usbd_errstr(err)); 847 return EIO; 848 } 849 } 850 return 0; 851 } 852 853 void 854 uchcom_close_intr_pipe(struct uchcom_softc *sc) 855 { 856 usbd_status err; 857 858 if (sc->sc_intr_pipe != NULL) { 859 err = usbd_close_pipe(sc->sc_intr_pipe); 860 if (err) 861 printf("%s: close interrupt pipe failed: %s\n", 862 sc->sc_dev.dv_xname, usbd_errstr(err)); 863 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize); 864 sc->sc_intr_pipe = NULL; 865 } 866 } 867 868 869 /* ---------------------------------------------------------------------- 870 * methods for ucom 871 */ 872 void 873 uchcom_get_status(void *arg, int portno, u_char *rlsr, u_char *rmsr) 874 { 875 struct uchcom_softc *sc = arg; 876 877 if (usbd_is_dying(sc->sc_udev)) 878 return; 879 880 *rlsr = sc->sc_lsr; 881 *rmsr = sc->sc_msr; 882 } 883 884 void 885 uchcom_set(void *arg, int portno, int reg, int onoff) 886 { 887 struct uchcom_softc *sc = arg; 888 889 if (usbd_is_dying(sc->sc_udev)) 890 return; 891 892 switch (reg) { 893 case UCOM_SET_DTR: 894 sc->sc_dtr = !!onoff; 895 uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 896 break; 897 case UCOM_SET_RTS: 898 sc->sc_rts = !!onoff; 899 uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 900 break; 901 case UCOM_SET_BREAK: 902 uchcom_set_break(sc, onoff); 903 break; 904 } 905 } 906 907 int 908 uchcom_param(void *arg, int portno, struct termios *t) 909 { 910 struct uchcom_softc *sc = arg; 911 int ret; 912 913 if (usbd_is_dying(sc->sc_udev)) 914 return 0; 915 916 ret = uchcom_set_line_control(sc, t->c_cflag); 917 if (ret) 918 return ret; 919 920 ret = uchcom_set_dte_rate(sc, t->c_ospeed); 921 if (ret) 922 return ret; 923 924 return 0; 925 } 926 927 int 928 uchcom_open(void *arg, int portno) 929 { 930 int ret; 931 struct uchcom_softc *sc = arg; 932 933 if (usbd_is_dying(sc->sc_udev)) 934 return EIO; 935 936 ret = uchcom_setup_intr_pipe(sc); 937 if (ret) 938 return ret; 939 940 ret = uchcom_setup_comm(sc); 941 if (ret) 942 return ret; 943 944 return 0; 945 } 946 947 void 948 uchcom_close(void *arg, int portno) 949 { 950 struct uchcom_softc *sc = arg; 951 952 uchcom_close_intr_pipe(sc); 953 } 954 955 956 /* ---------------------------------------------------------------------- 957 * callback when the modem status is changed. 958 */ 959 void 960 uchcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 961 { 962 struct uchcom_softc *sc = priv; 963 u_char *buf = sc->sc_intr_buf; 964 965 if (usbd_is_dying(sc->sc_udev)) 966 return; 967 968 if (status != USBD_NORMAL_COMPLETION) { 969 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 970 return; 971 972 DPRINTF(("%s: abnormal status: %s\n", 973 sc->sc_dev.dv_xname, usbd_errstr(status))); 974 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 975 return; 976 } 977 DPRINTF(("%s: intr: 0x%02X 0x%02X 0x%02X 0x%02X " 978 "0x%02X 0x%02X 0x%02X 0x%02X\n", 979 sc->sc_dev.dv_xname, 980 (unsigned)buf[0], (unsigned)buf[1], 981 (unsigned)buf[2], (unsigned)buf[3], 982 (unsigned)buf[4], (unsigned)buf[5], 983 (unsigned)buf[6], (unsigned)buf[7])); 984 985 uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]); 986 ucom_status_change((struct ucom_softc *) sc->sc_subdev); 987 } 988