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