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