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