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