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