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