1 /* $NetBSD: uchcom.c,v 1.1 2007/09/03 17:57:37 tshiozak 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.1 2007/09/03 17:57:37 tshiozak 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 USB_DECLARE_DRIVER(uchcom); 216 217 218 /* ---------------------------------------------------------------------- 219 * driver entry points 220 */ 221 222 USB_MATCH(uchcom) 223 { 224 USB_MATCH_START(uchcom, uaa); 225 226 return (uchcom_lookup(uaa->vendor, uaa->product) != NULL ? 227 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 228 } 229 230 USB_ATTACH(uchcom) 231 { 232 USB_ATTACH_START(uchcom, sc, uaa); 233 usbd_device_handle dev = uaa->device; 234 char *devinfop; 235 char *devname = USBDEVNAME(sc->sc_dev); 236 struct uchcom_endpoints endpoints; 237 struct ucom_attach_args uca; 238 239 devinfop = usbd_devinfo_alloc(dev, 0); 240 USB_ATTACH_SETUP; 241 printf("%s: %s\n", devname, devinfop); 242 usbd_devinfo_free(devinfop); 243 244 sc->sc_udev = dev; 245 sc->sc_dying = 0; 246 sc->sc_dtr = sc->sc_rts = -1; 247 sc->sc_lsr = sc->sc_msr = 0; 248 249 DPRINTF(("\n\nuchcom attach: sc=%p\n", sc)); 250 251 if (set_config(sc)) 252 goto failed; 253 254 switch (uaa->release) { 255 case UCHCOM_REV_CH340: 256 printf("%s: CH340 detected\n", devname); 257 break; 258 default: 259 printf("%s: CH341 detected\n", devname); 260 break; 261 } 262 263 if (find_ifaces(sc, &sc->sc_iface)) 264 goto failed; 265 266 if (find_endpoints(sc, &endpoints)) 267 goto failed; 268 269 sc->sc_intr_endpoint = endpoints.ep_intr; 270 sc->sc_intr_size = endpoints.ep_intr_size; 271 272 /* setup ucom layer */ 273 uca.portno = UCOM_UNK_PORTNO; 274 uca.bulkin = endpoints.ep_bulkin; 275 uca.bulkout = endpoints.ep_bulkout; 276 uca.ibufsize = UCHCOMIBUFSIZE; 277 uca.obufsize = UCHCOMOBUFSIZE; 278 uca.ibufsizepad = UCHCOMIBUFSIZE; 279 uca.opkthdrlen = 0; 280 uca.device = dev; 281 uca.iface = sc->sc_iface; 282 uca.methods = &uchcom_methods; 283 uca.arg = sc; 284 uca.info = NULL; 285 286 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 287 USBDEV(sc->sc_dev)); 288 289 sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca, 290 ucomprint, ucomsubmatch); 291 292 USB_ATTACH_SUCCESS_RETURN; 293 294 failed: 295 sc->sc_dying = 1; 296 USB_ATTACH_ERROR_RETURN; 297 } 298 299 USB_DETACH(uchcom) 300 { 301 USB_DETACH_START(uchcom, sc); 302 int rv = 0; 303 304 DPRINTF(("uchcom_detach: sc=%p flags=%d\n", sc, flags)); 305 306 close_intr_pipe(sc); 307 308 sc->sc_dying = 1; 309 310 if (sc->sc_subdev != NULL) { 311 rv = config_detach(sc->sc_subdev, flags); 312 sc->sc_subdev = NULL; 313 } 314 315 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 316 USBDEV(sc->sc_dev)); 317 318 return rv; 319 } 320 321 int 322 uchcom_activate(device_ptr_t self, enum devact act) 323 { 324 struct uchcom_softc *sc = (struct uchcom_softc *)self; 325 int rv = 0; 326 327 switch (act) { 328 case DVACT_ACTIVATE: 329 rv = EOPNOTSUPP; 330 break; 331 case DVACT_DEACTIVATE: 332 close_intr_pipe(sc); 333 sc->sc_dying = 1; 334 if (sc->sc_subdev != NULL) 335 rv = config_deactivate(sc->sc_subdev); 336 break; 337 } 338 return rv; 339 } 340 341 static int 342 set_config(struct uchcom_softc *sc) 343 { 344 usbd_status err; 345 346 err = usbd_set_config_index(sc->sc_udev, UCHCOM_CONFIG_INDEX, 1); 347 if (err) { 348 printf("%s: failed to set configuration: %s\n", 349 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 350 return -1; 351 } 352 353 return 0; 354 } 355 356 static int 357 find_ifaces(struct uchcom_softc *sc, usbd_interface_handle *riface) 358 { 359 usbd_status err; 360 361 err = usbd_device2interface_handle(sc->sc_udev, UCHCOM_IFACE_INDEX, 362 riface); 363 if (err) { 364 printf("\n%s: failed to get interface: %s\n", 365 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 366 return -1; 367 } 368 369 return 0; 370 } 371 372 static int 373 find_endpoints(struct uchcom_softc *sc, struct uchcom_endpoints *endpoints) 374 { 375 int i, bin=-1, bout=-1, intr=-1, isize=0; 376 usb_interface_descriptor_t *id; 377 usb_endpoint_descriptor_t *ed; 378 379 id = usbd_get_interface_descriptor(sc->sc_iface); 380 381 for (i = 0; i < id->bNumEndpoints; i++) { 382 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 383 if (ed == NULL) { 384 printf("%s: no endpoint descriptor for %d\n", 385 USBDEVNAME(sc->sc_dev), i); 386 return -1; 387 } 388 389 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 390 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 391 intr = ed->bEndpointAddress; 392 isize = UGETW(ed->wMaxPacketSize); 393 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 394 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 395 bin = ed->bEndpointAddress; 396 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 397 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 398 bout = ed->bEndpointAddress; 399 } 400 } 401 402 if (intr == -1 || bin == -1 || bout == -1) { 403 if (intr == -1) { 404 printf("%s: no interrupt end point\n", 405 USBDEVNAME(sc->sc_dev)); 406 } 407 if (bin == -1) { 408 printf("%s: no data bulk in end point\n", 409 USBDEVNAME(sc->sc_dev)); 410 } 411 if (bout == -1) { 412 printf("%s: no data bulk out end point\n", 413 USBDEVNAME(sc->sc_dev)); 414 } 415 return -1; 416 } 417 if (isize < UCHCOM_INTR_LEAST) { 418 printf("%s: intr pipe is too short", USBDEVNAME(sc->sc_dev)); 419 return -1; 420 } 421 422 DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n", 423 USBDEVNAME(sc->sc_dev), bin, bout, intr, isize)); 424 425 endpoints->ep_intr = intr; 426 endpoints->ep_intr_size = isize; 427 endpoints->ep_bulkin = bin; 428 endpoints->ep_bulkout = bout; 429 430 return 0; 431 } 432 433 434 /* ---------------------------------------------------------------------- 435 * low level i/o 436 */ 437 438 static __inline usbd_status 439 generic_control_out(struct uchcom_softc *sc, uint8_t reqno, 440 uint16_t value, uint16_t index) 441 { 442 usb_device_request_t req; 443 444 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 445 req.bRequest = reqno; 446 USETW(req.wValue, value); 447 USETW(req.wIndex, index); 448 USETW(req.wLength, 0); 449 450 return usbd_do_request(sc->sc_udev, &req, 0); 451 } 452 453 static __inline usbd_status 454 generic_control_in(struct uchcom_softc *sc, uint8_t reqno, 455 uint16_t value, uint16_t index, void *buf, int buflen, 456 int *actlen) 457 { 458 usb_device_request_t req; 459 460 req.bmRequestType = UT_READ_VENDOR_DEVICE; 461 req.bRequest = reqno; 462 USETW(req.wValue, value); 463 USETW(req.wIndex, index); 464 USETW(req.wLength, (uint16_t)buflen); 465 466 return usbd_do_request_flags(sc->sc_udev, &req, buf, 467 USBD_SHORT_XFER_OK, actlen, 468 USBD_DEFAULT_TIMEOUT); 469 } 470 471 static __inline usbd_status 472 write_reg(struct uchcom_softc *sc, 473 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2) 474 { 475 DPRINTF(("uchcom: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n", 476 (unsigned)reg1, (unsigned)val1, 477 (unsigned)reg2, (unsigned)val2)); 478 return generic_control_out( 479 sc, UCHCOM_REQ_WRITE_REG, 480 reg1|((uint16_t)reg2<<8), val1|((uint16_t)val2<<8)); 481 } 482 483 static __inline usbd_status 484 read_reg(struct uchcom_softc *sc, 485 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2) 486 { 487 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 488 usbd_status err; 489 int actin; 490 491 err = generic_control_in( 492 sc, UCHCOM_REQ_READ_REG, 493 reg1|((uint16_t)reg2<<8), 0, buf, sizeof buf, &actin); 494 if (err) 495 return err; 496 497 DPRINTF(("uchcom: read reg 0x%02X->0x%02X, 0x%02X->0x%02X\n", 498 (unsigned)reg1, (unsigned)buf[0], 499 (unsigned)reg2, (unsigned)buf[1])); 500 501 if (rval1) *rval1 = buf[0]; 502 if (rval2) *rval2 = buf[1]; 503 504 return USBD_NORMAL_COMPLETION; 505 } 506 507 static __inline usbd_status 508 get_version(struct uchcom_softc *sc, uint8_t *rver) 509 { 510 uint8_t buf[UCHCOM_INPUT_BUF_SIZE]; 511 usbd_status err; 512 int actin; 513 514 err = generic_control_in( 515 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof buf, &actin); 516 if (err) 517 return err; 518 519 if (rver) *rver = buf[0]; 520 521 return USBD_NORMAL_COMPLETION; 522 } 523 524 static __inline usbd_status 525 get_status(struct uchcom_softc *sc, uint8_t *rval) 526 { 527 return read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, NULL); 528 } 529 530 static __inline usbd_status 531 set_dtrrts_10(struct uchcom_softc *sc, uint8_t val) 532 { 533 return write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val); 534 } 535 536 static __inline usbd_status 537 set_dtrrts_20(struct uchcom_softc *sc, uint8_t val) 538 { 539 return generic_control_out(sc, UCHCOM_REQ_SET_DTRRTS, val, 0); 540 } 541 542 543 /* ---------------------------------------------------------------------- 544 * middle layer 545 */ 546 547 static int 548 update_version(struct uchcom_softc *sc) 549 { 550 usbd_status err; 551 552 err = get_version(sc, &sc->sc_version); 553 if (err) { 554 printf("%s: cannot get version: %s\n", 555 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 556 return EIO; 557 } 558 559 return 0; 560 } 561 562 static void 563 convert_status(struct uchcom_softc *sc, uint8_t cur) 564 { 565 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK); 566 sc->sc_rts = !(cur & UCHCOM_RTS_MASK); 567 568 cur = ~cur & 0x0F; 569 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur); 570 } 571 572 static int 573 update_status(struct uchcom_softc *sc) 574 { 575 usbd_status err; 576 uint8_t cur; 577 578 err = get_status(sc, &cur); 579 if (err) { 580 printf("%s: cannot update status: %s\n", 581 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 582 return EIO; 583 } 584 convert_status(sc, cur); 585 586 return 0; 587 } 588 589 590 static int 591 set_dtrrts(struct uchcom_softc *sc, int dtr, int rts) 592 { 593 usbd_status err; 594 uint8_t val = 0; 595 596 if (dtr) val |= UCHCOM_DTR_MASK; 597 if (rts) val |= UCHCOM_RTS_MASK; 598 599 if (sc->sc_version < UCHCOM_VER_20) 600 err = set_dtrrts_10(sc, ~val); 601 else 602 err = set_dtrrts_20(sc, ~val); 603 604 if (err) { 605 printf("%s: cannot set DTR/RTS: %s\n", 606 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 607 return EIO; 608 } 609 610 return 0; 611 } 612 613 static int 614 set_break(struct uchcom_softc *sc, int onoff) 615 { 616 usbd_status err; 617 uint8_t brk1, brk2; 618 619 err = read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2); 620 if (err) 621 return EIO; 622 if (onoff) { 623 /* on - clear bits */ 624 brk1 &= ~UCHCOM_BRK1_MASK; 625 brk2 &= ~UCHCOM_BRK2_MASK; 626 } else { 627 /* off - set bits */ 628 brk1 |= UCHCOM_BRK1_MASK; 629 brk2 |= UCHCOM_BRK2_MASK; 630 } 631 err = write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2); 632 if (err) 633 return EIO; 634 635 return 0; 636 } 637 638 static int 639 calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) 640 { 641 int i; 642 const struct uchcom_divider_record *rp; 643 uint32_t div, rem, mod; 644 645 /* find record */ 646 for (i=0; i<NUM_DIVIDERS; i++) { 647 if (dividers[i].dvr_high >= rate && 648 dividers[i].dvr_low <= rate) { 649 rp = ÷rs[i]; 650 goto found; 651 } 652 } 653 return -1; 654 655 found: 656 dp->dv_prescaler = rp->dvr_divider.dv_prescaler; 657 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN) 658 dp->dv_div = rp->dvr_divider.dv_div; 659 else { 660 div = rp->dvr_base_clock / rate; 661 rem = rp->dvr_base_clock % rate; 662 if (div==0 || div>=0xFF) 663 return -1; 664 if ((rem<<1) >= rate) 665 div += 1; 666 dp->dv_div = (uint8_t)-div; 667 } 668 669 mod = UCHCOM_BPS_MOD_BASE/rate + UCHCOM_BPS_MOD_BASE_OFS; 670 mod = mod + mod/2; 671 672 dp->dv_mod = mod / 0x100; 673 674 return 0; 675 } 676 677 static int 678 set_dte_rate(struct uchcom_softc *sc, uint32_t rate) 679 { 680 usbd_status err; 681 struct uchcom_divider dv; 682 683 if (calc_divider_settings(&dv, rate)) 684 return EINVAL; 685 686 if ((err = write_reg(sc, 687 UCHCOM_REG_BPS_PRE, dv.dv_prescaler, 688 UCHCOM_REG_BPS_DIV, dv.dv_div)) || 689 (err = write_reg(sc, 690 UCHCOM_REG_BPS_MOD, dv.dv_mod, 691 UCHCOM_REG_BPS_PAD, 0))) { 692 printf("%s: cannot set DTE rate: %s\n", 693 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 694 return EIO; 695 } 696 697 return 0; 698 } 699 700 static int 701 set_line_control(struct uchcom_softc *sc, tcflag_t cflag) 702 { 703 usbd_status err; 704 uint8_t lcr1 = 0, lcr2 = 0; 705 706 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 707 if (err) { 708 printf("%s: cannot get LCR: %s\n", 709 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 710 return EIO; 711 } 712 713 lcr1 &= ~UCHCOM_LCR1_MASK; 714 lcr2 &= ~UCHCOM_LCR2_MASK; 715 716 /* 717 * XXX: it is difficult to handle the line control appropriately: 718 * - CS8, !CSTOPB and any parity mode seems ok, but 719 * - the chip doesn't have the function to calculate parity 720 * in !CS8 mode. 721 * - it is unclear that the chip supports CS5,6 mode. 722 * - it is unclear how to handle stop bits. 723 */ 724 725 switch (ISSET(cflag, CSIZE)) { 726 case CS5: 727 case CS6: 728 case CS7: 729 return EINVAL; 730 case CS8: 731 break; 732 } 733 734 if (ISSET(cflag, PARENB)) { 735 lcr1 |= UCHCOM_LCR1_PARENB; 736 if (ISSET(cflag, PARODD)) 737 lcr2 |= UCHCOM_LCR2_PARODD; 738 else 739 lcr2 |= UCHCOM_LCR2_PAREVEN; 740 } 741 742 err = write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2, lcr2); 743 if (err) { 744 printf("%s: cannot set LCR: %s\n", 745 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 746 return EIO; 747 } 748 749 return 0; 750 } 751 752 static int 753 clear_chip(struct uchcom_softc *sc) 754 { 755 usbd_status err; 756 757 DPRINTF(("%s: clear\n", USBDEVNAME(sc->sc_dev))); 758 err = generic_control_out(sc, UCHCOM_REQ_RESET, 0, 0); 759 if (err) { 760 printf("%s: cannot clear: %s\n", 761 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 762 return EIO; 763 } 764 765 return 0; 766 } 767 768 static int 769 reset_chip(struct uchcom_softc *sc) 770 { 771 usbd_status err; 772 uint8_t lcr1, lcr2, pre, div, mod; 773 uint16_t val=0, idx=0; 774 775 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2); 776 if (err) 777 goto failed; 778 779 err = read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV, &div); 780 if (err) 781 goto failed; 782 783 err = read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD, NULL); 784 if (err) 785 goto failed; 786 787 val |= (uint16_t)(lcr1&0xF0) << 8; 788 val |= 0x01; 789 val |= (uint16_t)(lcr2&0x0F) << 8; 790 val |= 0x02; 791 idx |= pre & 0x07; 792 val |= 0x04; 793 idx |= (uint16_t)div << 8; 794 val |= 0x08; 795 idx |= mod & 0xF8; 796 val |= 0x10; 797 798 DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n", 799 USBDEVNAME(sc->sc_dev), val, idx)); 800 801 err = generic_control_out(sc, UCHCOM_REQ_RESET, val, idx); 802 if (err) 803 goto failed; 804 805 return 0; 806 807 failed: 808 printf("%s: cannot reset: %s\n", 809 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 810 return EIO; 811 } 812 813 static int 814 setup_comm(struct uchcom_softc *sc) 815 { 816 int ret; 817 818 ret = update_version(sc); 819 if (ret) 820 return ret; 821 822 ret = clear_chip(sc); 823 if (ret) 824 return ret; 825 826 ret = set_dte_rate(sc, TTYDEF_SPEED); 827 if (ret) 828 return ret; 829 830 ret = set_line_control(sc, CS8); 831 if (ret) 832 return ret; 833 834 ret = update_status(sc); 835 if (ret) 836 return ret; 837 838 ret = reset_chip(sc); 839 if (ret) 840 return ret; 841 842 ret = set_dte_rate(sc, TTYDEF_SPEED); /* XXX */ 843 if (ret) 844 return ret; 845 846 sc->sc_dtr = sc->sc_rts = 1; 847 ret = set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 848 if (ret) 849 return ret; 850 851 return 0; 852 } 853 854 static int 855 setup_intr_pipe(struct uchcom_softc *sc) 856 { 857 usbd_status err; 858 859 if (sc->sc_intr_endpoint != -1 && sc->sc_intr_pipe == NULL) { 860 sc->sc_intr_buf = malloc(sc->sc_intr_size, M_USBDEV, M_WAITOK); 861 err = usbd_open_pipe_intr(sc->sc_iface, 862 sc->sc_intr_endpoint, 863 USBD_SHORT_XFER_OK, 864 &sc->sc_intr_pipe, sc, 865 sc->sc_intr_buf, 866 sc->sc_intr_size, 867 uchcom_intr, USBD_DEFAULT_INTERVAL); 868 if (err) { 869 printf("%s: cannot open interrupt pipe: %s\n", 870 USBDEVNAME(sc->sc_dev), 871 usbd_errstr(err)); 872 return EIO; 873 } 874 } 875 return 0; 876 } 877 878 static void 879 close_intr_pipe(struct uchcom_softc *sc) 880 { 881 usbd_status err; 882 883 if (sc->sc_dying) 884 return; 885 886 if (sc->sc_intr_pipe != NULL) { 887 err = usbd_abort_pipe(sc->sc_intr_pipe); 888 if (err) 889 printf("%s: abort interrupt pipe failed: %s\n", 890 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 891 err = usbd_close_pipe(sc->sc_intr_pipe); 892 if (err) 893 printf("%s: close interrupt pipe failed: %s\n", 894 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 895 free(sc->sc_intr_buf, M_USBDEV); 896 sc->sc_intr_pipe = NULL; 897 } 898 } 899 900 901 /* ---------------------------------------------------------------------- 902 * methods for ucom 903 */ 904 void 905 uchcom_get_status(void *arg, int portno, u_char *rlsr, u_char *rmsr) 906 { 907 struct uchcom_softc *sc = arg; 908 909 if (sc->sc_dying) 910 return; 911 912 *rlsr = sc->sc_lsr; 913 *rmsr = sc->sc_msr; 914 } 915 916 void 917 uchcom_set(void *arg, int portno, int reg, int onoff) 918 { 919 struct uchcom_softc *sc = arg; 920 921 if (sc->sc_dying) 922 return; 923 924 switch (reg) { 925 case UCOM_SET_DTR: 926 sc->sc_dtr = !!onoff; 927 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 928 break; 929 case UCOM_SET_RTS: 930 sc->sc_rts = !!onoff; 931 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); 932 break; 933 case UCOM_SET_BREAK: 934 set_break(sc, onoff); 935 break; 936 } 937 } 938 939 int 940 uchcom_param(void *arg, int portno, struct termios *t) 941 { 942 struct uchcom_softc *sc = arg; 943 int ret; 944 945 if (sc->sc_dying) 946 return 0; 947 948 ret = set_line_control(sc, t->c_cflag); 949 if (ret) 950 return ret; 951 952 ret = set_dte_rate(sc, t->c_ospeed); 953 if (ret) 954 return ret; 955 956 return 0; 957 } 958 959 int 960 uchcom_open(void *arg, int portno) 961 { 962 int ret; 963 struct uchcom_softc *sc = arg; 964 965 if (sc->sc_dying) 966 return EIO; 967 968 ret = setup_intr_pipe(sc); 969 if (ret) 970 return ret; 971 972 ret = setup_comm(sc); 973 if (ret) 974 return ret; 975 976 return 0; 977 } 978 979 void 980 uchcom_close(void *arg, int portno) 981 { 982 struct uchcom_softc *sc = arg; 983 984 if (sc->sc_dying) 985 return; 986 987 close_intr_pipe(sc); 988 } 989 990 991 /* ---------------------------------------------------------------------- 992 * callback when the modem status is changed. 993 */ 994 void 995 uchcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 996 usbd_status status) 997 { 998 struct uchcom_softc *sc = priv; 999 u_char *buf = sc->sc_intr_buf; 1000 1001 if (sc->sc_dying) 1002 return; 1003 1004 if (status != USBD_NORMAL_COMPLETION) { 1005 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1006 return; 1007 1008 DPRINTF(("%s: abnormal status: %s\n", 1009 USBDEVNAME(sc->sc_dev), usbd_errstr(status))); 1010 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 1011 return; 1012 } 1013 DPRINTF(("%s: intr: 0x%02X 0x%02X 0x%02X 0x%02X " 1014 "0x%02X 0x%02X 0x%02X 0x%02X\n", 1015 USBDEVNAME(sc->sc_dev), 1016 (unsigned)buf[0], (unsigned)buf[1], 1017 (unsigned)buf[2], (unsigned)buf[3], 1018 (unsigned)buf[4], (unsigned)buf[5], 1019 (unsigned)buf[6], (unsigned)buf[7])); 1020 1021 convert_status(sc, buf[UCHCOM_INTR_STAT1]); 1022 ucom_status_change((struct ucom_softc *) sc->sc_subdev); 1023 } 1024