1 /* $OpenBSD: umcs.c,v 1.12 2024/05/23 03:21:09 jsg Exp $ */ 2 /* $NetBSD: umcs.c,v 1.8 2014/08/23 21:37:56 martin Exp $ */ 3 /* $FreeBSD: head/sys/dev/usb/serial/umcs.c 260559 2014-01-12 11:44:28Z hselasky $ */ 4 5 /*- 6 * Copyright (c) 2010 Lev Serebryakov <lev@FreeBSD.org>. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * This driver supports several multiport USB-to-RS232 serial adapters driven 33 * by MosChip mos7820 and mos7840, bridge chips. The adapters are sold under 34 * many different brand names. 35 * 36 * Datasheets are available at MosChip www site at http://www.moschip.com. 37 * The datasheets don't contain full programming information for the chip. 38 * 39 * It is normal to have only two enabled ports in devices, based on quad-port 40 * mos7840. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/malloc.h> 46 #include <sys/tty.h> 47 #include <sys/device.h> 48 #include <sys/task.h> 49 50 #include <dev/usb/usb.h> 51 #include <dev/usb/usbdi.h> 52 #include <dev/usb/usbdevs.h> 53 54 #include <dev/usb/ucomvar.h> 55 56 #include "umcs.h" 57 58 #ifdef UMCS_DEBUG 59 #define DPRINTF(x...) printf(x) 60 #else 61 #define DPRINTF(x...) 62 #endif 63 64 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) 65 66 /* 67 * Two-port devices (both with 7820 chip and 7840 chip configured as two-port) 68 * have ports 0 and 2, with ports 1 and 3 omitted. 69 * So, PHYSICAL port numbers on two-port device will be 0 and 2. 70 * 71 * We use an array of the following struct, indexed by ucom port index, 72 * and include the physical port number in it. 73 */ 74 struct umcs_port { 75 struct ucom_softc *ucom; /* ucom subdevice */ 76 unsigned int pn; /* physical port number */ 77 int flags; 78 #define UMCS_STATCHG 0x01 79 80 uint8_t lcr; /* local line control reg. */ 81 uint8_t mcr; /* local modem control reg. */ 82 }; 83 84 struct umcs_softc { 85 struct device sc_dev; 86 struct usbd_device *sc_udev; /* the usb device */ 87 struct usbd_pipe *sc_ipipe; /* interrupt pipe */ 88 uint8_t *sc_ibuf; /* buffer for interrupt xfer */ 89 unsigned int sc_isize; /* size of buffer */ 90 91 struct umcs_port sc_subdevs[UMCS_MAX_PORTS]; 92 uint8_t sc_numports; /* number of ports */ 93 94 int sc_init_done; 95 struct task sc_status_task; 96 }; 97 98 int umcs_get_reg(struct umcs_softc *, uint8_t, uint8_t *); 99 int umcs_set_reg(struct umcs_softc *, uint8_t, uint8_t); 100 int umcs_get_uart_reg(struct umcs_softc *, uint8_t, uint8_t, uint8_t *); 101 int umcs_set_uart_reg(struct umcs_softc *, uint8_t, uint8_t, uint8_t); 102 int umcs_calc_baudrate(uint32_t, uint16_t *, uint8_t *); 103 int umcs_set_baudrate(struct umcs_softc *, uint8_t, uint32_t); 104 void umcs_dtr(struct umcs_softc *, int, int); 105 void umcs_rts(struct umcs_softc *, int, int); 106 void umcs_break(struct umcs_softc *, int, int); 107 108 int umcs_match(struct device *, void *, void *); 109 void umcs_attach(struct device *, struct device *, void *); 110 int umcs_detach(struct device *, int); 111 void umcs_intr(struct usbd_xfer *, void *, usbd_status); 112 void umcs_status_task(void *); 113 114 void umcs_get_status(void *, int, uint8_t *, uint8_t *); 115 void umcs_set(void *, int, int, int); 116 int umcs_param(void *, int, struct termios *); 117 int umcs_open(void *, int); 118 void umcs_close(void *, int); 119 120 const struct ucom_methods umcs_methods = { 121 umcs_get_status, 122 umcs_set, 123 umcs_param, 124 NULL, 125 umcs_open, 126 umcs_close, 127 NULL, 128 NULL, 129 }; 130 131 const struct usb_devno umcs_devs[] = { 132 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7810 }, 133 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7820 }, 134 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7840 }, 135 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC2324 } 136 }; 137 138 struct cfdriver umcs_cd = { 139 NULL, "umcs", DV_DULL 140 }; 141 142 const struct cfattach umcs_ca = { 143 sizeof(struct umcs_softc), umcs_match, umcs_attach, umcs_detach 144 }; 145 146 147 static inline int 148 umcs_reg_sp(int pn) 149 { 150 KASSERT(pn >= 0 && pn < 4); 151 switch (pn) { 152 default: 153 case 0: return UMCS_SP1; 154 case 1: return UMCS_SP2; 155 case 2: return UMCS_SP3; 156 case 3: return UMCS_SP4; 157 } 158 } 159 160 static inline int 161 umcs_reg_ctrl(int pn) 162 { 163 KASSERT(pn >= 0 && pn < 4); 164 switch (pn) { 165 default: 166 case 0: return UMCS_CTRL1; 167 case 1: return UMCS_CTRL2; 168 case 2: return UMCS_CTRL3; 169 case 3: return UMCS_CTRL4; 170 } 171 } 172 173 int 174 umcs_match(struct device *dev, void *match, void *aux) 175 { 176 struct usb_attach_arg *uaa = aux; 177 178 if (uaa->iface == NULL || uaa->ifaceno != UMCS_IFACE_NO) 179 return (UMATCH_NONE); 180 181 return (usb_lookup(umcs_devs, uaa->vendor, uaa->product) != NULL) ? 182 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 183 } 184 185 void 186 umcs_attach(struct device *parent, struct device *self, void *aux) 187 { 188 struct umcs_softc *sc = (struct umcs_softc *)self; 189 struct usb_attach_arg *uaa = aux; 190 usb_interface_descriptor_t *id; 191 usb_endpoint_descriptor_t *ed; 192 struct ucom_attach_args uca; 193 int error, i, intr_addr; 194 uint8_t data; 195 196 sc->sc_udev = uaa->device; 197 198 /* 199 * Get number of ports 200 * Documentation (full datasheet) says, that number of ports is 201 * set as UMCS_MODE_SELECT24S bit in MODE R/Only 202 * register. But vendor driver uses these undocumented 203 * register & bit. 204 * 205 * Experiments show, that MODE register can have `0' 206 * (4 ports) bit on 2-port device, so use vendor driver's way. 207 * 208 * Also, see notes in header file for these constants. 209 */ 210 if (umcs_get_reg(sc, UMCS_GPIO, &data)) { 211 printf("%s: unable to get number of ports\n", DEVNAME(sc)); 212 usbd_deactivate(sc->sc_udev); 213 return; 214 } 215 if (data & UMCS_GPIO_4PORTS) 216 sc->sc_numports = 4; /* physical port no are : 0, 1, 2, 3 */ 217 else if (uaa->product == USB_PRODUCT_MOSCHIP_MCS7810) 218 sc->sc_numports = 1; 219 else 220 sc->sc_numports = 2; /* physical port no are: 0 and 2 */ 221 222 #ifdef UMCS_DEBUG 223 if (!umcs_get_reg(sc, UMCS_MODE, &data)) { 224 printf("%s: On-die configuration: RST: active %s, " 225 "HRD: %s, PLL: %s, POR: %s, Ports: %s, EEPROM write %s, " 226 "IrDA is %savailable\n", DEVNAME(sc), 227 (data & UMCS_MODE_RESET) ? "low" : "high", 228 (data & UMCS_MODE_SER_PRSNT) ? "yes" : "no", 229 (data & UMCS_MODE_PLLBYPASS) ? "bypassed" : "avail", 230 (data & UMCS_MODE_PORBYPASS) ? "bypassed" : "avail", 231 (data & UMCS_MODE_SELECT24S) ? "2" : "4", 232 (data & UMCS_MODE_EEPROMWR) ? "enabled" : "disabled", 233 (data & UMCS_MODE_IRDA) ? "" : "not "); 234 } 235 #endif 236 237 /* Set up the interrupt pipe */ 238 id = usbd_get_interface_descriptor(uaa->iface); 239 intr_addr = -1; 240 for (i = 0 ; i < id->bNumEndpoints ; i++) { 241 ed = usbd_interface2endpoint_descriptor(uaa->iface, i); 242 if (ed == NULL) { 243 printf("%s: no endpoint descriptor found for %d\n", 244 DEVNAME(sc), i); 245 usbd_deactivate(sc->sc_udev); 246 return; 247 } 248 249 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || 250 UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) 251 continue; 252 sc->sc_isize = UGETW(ed->wMaxPacketSize); 253 intr_addr = ed->bEndpointAddress; 254 break; 255 } 256 if (intr_addr < 0) { 257 printf("%s: missing endpoint\n", DEVNAME(sc)); 258 usbd_deactivate(sc->sc_udev); 259 return; 260 } 261 sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 262 263 error = usbd_open_pipe_intr(uaa->iface, intr_addr, 264 USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf, 265 sc->sc_isize, umcs_intr, 100 /* XXX */); 266 if (error) { 267 printf("%s: cannot open interrupt pipe (addr %d)\n", 268 DEVNAME(sc), intr_addr); 269 usbd_deactivate(sc->sc_udev); 270 return; 271 } 272 273 memset(&uca, 0, sizeof uca); 274 uca.ibufsize = 256; 275 uca.obufsize = 256; 276 uca.ibufsizepad = 256; 277 uca.opkthdrlen = 0; 278 uca.device = sc->sc_udev; 279 uca.iface = uaa->iface; 280 uca.methods = &umcs_methods; 281 uca.arg = sc; 282 283 for (i = 0; i < sc->sc_numports; i++) { 284 uca.bulkin = uca.bulkout = -1; 285 286 /* 287 * On 4 port cards, endpoints are 0/1, 2/3, 4/5, and 6/7. 288 * On 2 port cards, they are 0/1 and 4/5. 289 * On single port, just 0/1 will be used. 290 */ 291 int pn = i * (sc->sc_numports == 2 ? 2 : 1); 292 293 ed = usbd_interface2endpoint_descriptor(uaa->iface, pn*2); 294 if (ed == NULL) { 295 printf("%s: no bulk in endpoint found for %d\n", 296 DEVNAME(sc), i); 297 usbd_deactivate(sc->sc_udev); 298 return; 299 } 300 uca.bulkin = ed->bEndpointAddress; 301 302 ed = usbd_interface2endpoint_descriptor(uaa->iface, pn*2+1); 303 if (ed == NULL) { 304 printf("%s: no bulk out endpoint found for %d\n", 305 DEVNAME(sc), i); 306 usbd_deactivate(sc->sc_udev); 307 return; 308 } 309 uca.bulkout = ed->bEndpointAddress; 310 uca.portno = i; 311 312 sc->sc_subdevs[i].pn = pn; 313 sc->sc_subdevs[i].ucom = (struct ucom_softc *) 314 config_found_sm(self, &uca, ucomprint, ucomsubmatch); 315 } 316 317 task_set(&sc->sc_status_task, umcs_status_task, sc); 318 } 319 320 int 321 umcs_get_reg(struct umcs_softc *sc, uint8_t reg, uint8_t *data) 322 { 323 usb_device_request_t req; 324 325 req.bmRequestType = UT_READ_VENDOR_DEVICE; 326 req.bRequest = UMCS_READ; 327 USETW(req.wValue, 0); 328 USETW(req.wIndex, reg); 329 USETW(req.wLength, UMCS_READ_LENGTH); 330 331 if (usbd_do_request(sc->sc_udev, &req, data)) 332 return (EIO); 333 334 return (0); 335 } 336 337 int 338 umcs_set_reg(struct umcs_softc *sc, uint8_t reg, uint8_t data) 339 { 340 usb_device_request_t req; 341 342 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 343 req.bRequest = UMCS_WRITE; 344 USETW(req.wValue, data); 345 USETW(req.wIndex, reg); 346 USETW(req.wLength, 0); 347 348 if (usbd_do_request(sc->sc_udev, &req, NULL)) 349 return (EIO); 350 351 return (0); 352 } 353 354 int 355 umcs_get_uart_reg(struct umcs_softc *sc, uint8_t portno, uint8_t reg, 356 uint8_t *data) 357 { 358 usb_device_request_t req; 359 uint16_t wVal; 360 361 wVal = ((uint16_t)(sc->sc_subdevs[portno].pn + 1)) << 8; 362 363 req.bmRequestType = UT_READ_VENDOR_DEVICE; 364 req.bRequest = UMCS_READ; 365 USETW(req.wValue, wVal); 366 USETW(req.wIndex, reg); 367 USETW(req.wLength, UMCS_READ_LENGTH); 368 369 if (usbd_do_request(sc->sc_udev, &req, data)) 370 return (EIO); 371 372 return (0); 373 } 374 375 int 376 umcs_set_uart_reg(struct umcs_softc *sc, uint8_t portno, uint8_t reg, 377 uint8_t data) 378 { 379 usb_device_request_t req; 380 uint16_t wVal; 381 382 wVal = ((uint16_t)(sc->sc_subdevs[portno].pn + 1)) << 8 | data; 383 384 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 385 req.bRequest = UMCS_WRITE; 386 USETW(req.wValue, wVal); 387 USETW(req.wIndex, reg); 388 USETW(req.wLength, 0); 389 390 if (usbd_do_request(sc->sc_udev, &req, NULL)) 391 return (EIO); 392 393 return (0); 394 } 395 396 int 397 umcs_set_baudrate(struct umcs_softc *sc, uint8_t portno, uint32_t rate) 398 { 399 int pn = sc->sc_subdevs[portno].pn; 400 int spreg = umcs_reg_sp(pn); 401 uint8_t lcr = sc->sc_subdevs[portno].lcr; 402 uint8_t clk, data; 403 uint16_t div; 404 405 if (umcs_calc_baudrate(rate, &div, &clk)) 406 return (EINVAL); 407 408 DPRINTF("%s: portno %d set speed: %d (%02x/%d)\n", DEVNAME(sc), portno, 409 rate, clk, div); 410 411 /* Set clock source for standard BAUD frequencies */ 412 if (umcs_get_reg(sc, spreg, &data)) 413 return (EIO); 414 data &= UMCS_SPx_CLK_MASK; 415 if (umcs_set_reg(sc, spreg, data | clk)) 416 return (EIO); 417 418 /* Set divider */ 419 lcr |= UMCS_LCR_DIVISORS; 420 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr)) 421 return (EIO); 422 sc->sc_subdevs[portno].lcr = lcr; 423 424 if (umcs_set_uart_reg(sc, portno, UMCS_REG_DLL, div & 0xff) || 425 umcs_set_uart_reg(sc, portno, UMCS_REG_DLM, (div >> 8) & 0xff)) 426 return (EIO); 427 428 /* Turn off access to DLL/DLM registers of UART */ 429 lcr &= ~UMCS_LCR_DIVISORS; 430 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr)) 431 return (EIO); 432 sc->sc_subdevs[portno].lcr = lcr; 433 434 return (0); 435 } 436 437 /* Maximum speeds for standard frequencies, when PLL is not used */ 438 static const uint32_t umcs_baudrate_divisors[] = { 439 0, 115200, 230400, 403200, 460800, 806400, 921600, 1572864, 3145728, 440 }; 441 442 int 443 umcs_calc_baudrate(uint32_t rate, uint16_t *divisor, uint8_t *clk) 444 { 445 const uint8_t divisors_len = nitems(umcs_baudrate_divisors); 446 uint8_t i = 0; 447 448 if (rate > umcs_baudrate_divisors[divisors_len - 1]) 449 return (-1); 450 451 for (i = 0; i < divisors_len - 1; i++) { 452 if (rate > umcs_baudrate_divisors[i] && 453 rate <= umcs_baudrate_divisors[i + 1]) { 454 *divisor = umcs_baudrate_divisors[i + 1] / rate; 455 /* 0x00 .. 0x70 */ 456 *clk = i << UMCS_SPx_CLK_SHIFT; 457 return (0); 458 } 459 } 460 461 return (-1); 462 } 463 464 int 465 umcs_detach(struct device *self, int flags) 466 { 467 struct umcs_softc *sc = (struct umcs_softc *)self; 468 469 task_del(systq, &sc->sc_status_task); 470 471 if (sc->sc_ipipe != NULL) { 472 usbd_close_pipe(sc->sc_ipipe); 473 sc->sc_ipipe = NULL; 474 } 475 476 if (sc->sc_ibuf != NULL) { 477 free(sc->sc_ibuf, M_USBDEV, sc->sc_isize); 478 sc->sc_ibuf = NULL; 479 } 480 481 return (config_detach_children(self, flags)); 482 } 483 484 void 485 umcs_get_status(void *self, int portno, uint8_t *lsr, uint8_t *msr) 486 { 487 struct umcs_softc *sc = self; 488 uint8_t hw_lsr = 0; /* local line status register */ 489 uint8_t hw_msr = 0; /* local modem status register */ 490 491 if (usbd_is_dying(sc->sc_udev)) 492 return; 493 494 /* Read LSR & MSR */ 495 if (umcs_get_uart_reg(sc, portno, UMCS_REG_LSR, &hw_lsr) || 496 umcs_get_uart_reg(sc, portno, UMCS_REG_MSR, &hw_msr)) 497 return; 498 499 *lsr = hw_lsr; 500 *msr = hw_msr; 501 } 502 503 void 504 umcs_set(void *self, int portno, int reg, int onoff) 505 { 506 struct umcs_softc *sc = self; 507 508 if (usbd_is_dying(sc->sc_udev)) 509 return; 510 511 switch (reg) { 512 case UCOM_SET_DTR: 513 umcs_dtr(sc, portno, onoff); 514 break; 515 case UCOM_SET_RTS: 516 umcs_rts(sc, portno, onoff); 517 break; 518 case UCOM_SET_BREAK: 519 umcs_break(sc, portno, onoff); 520 break; 521 default: 522 break; 523 } 524 } 525 526 int 527 umcs_param(void *self, int portno, struct termios *t) 528 { 529 struct umcs_softc *sc = self; 530 uint8_t lcr = sc->sc_subdevs[portno].lcr; 531 uint8_t mcr = sc->sc_subdevs[portno].mcr; 532 int error = 0; 533 534 if (t->c_cflag & CSTOPB) 535 lcr |= UMCS_LCR_STOPB2; 536 else 537 lcr |= UMCS_LCR_STOPB1; 538 539 lcr &= ~UMCS_LCR_PARITYMASK; 540 if (t->c_cflag & PARENB) { 541 lcr |= UMCS_LCR_PARITYON; 542 if (t->c_cflag & PARODD) { 543 lcr |= UMCS_LCR_PARITYODD; 544 } else { 545 lcr |= UMCS_LCR_PARITYEVEN; 546 } 547 } else { 548 lcr &= ~UMCS_LCR_PARITYON; 549 } 550 551 lcr &= ~UMCS_LCR_DATALENMASK; 552 switch (t->c_cflag & CSIZE) { 553 case CS5: 554 lcr |= UMCS_LCR_DATALEN5; 555 break; 556 case CS6: 557 lcr |= UMCS_LCR_DATALEN6; 558 break; 559 case CS7: 560 lcr |= UMCS_LCR_DATALEN7; 561 break; 562 case CS8: 563 lcr |= UMCS_LCR_DATALEN8; 564 break; 565 } 566 567 if (t->c_cflag & CRTSCTS) 568 mcr |= UMCS_MCR_CTSRTS; 569 else 570 mcr &= ~UMCS_MCR_CTSRTS; 571 572 if (t->c_cflag & CLOCAL) 573 mcr &= ~UMCS_MCR_DTRDSR; 574 else 575 mcr |= UMCS_MCR_DTRDSR; 576 577 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr)) 578 return (EIO); 579 sc->sc_subdevs[portno].lcr = lcr; 580 581 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr)) 582 return (EIO); 583 sc->sc_subdevs[portno].mcr = mcr; 584 585 error = umcs_set_baudrate(sc, portno, t->c_ospeed); 586 587 return (error); 588 } 589 590 void 591 umcs_dtr(struct umcs_softc *sc, int portno, int onoff) 592 { 593 uint8_t mcr = sc->sc_subdevs[portno].mcr; 594 595 if (onoff) 596 mcr |= UMCS_MCR_DTR; 597 else 598 mcr &= ~UMCS_MCR_DTR; 599 600 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr)) 601 return; 602 sc->sc_subdevs[portno].mcr = mcr; 603 } 604 605 void 606 umcs_rts(struct umcs_softc *sc, int portno, int onoff) 607 { 608 uint8_t mcr = sc->sc_subdevs[portno].mcr; 609 610 if (onoff) 611 mcr |= UMCS_MCR_RTS; 612 else 613 mcr &= ~UMCS_MCR_RTS; 614 615 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr)) 616 return; 617 sc->sc_subdevs[portno].mcr = mcr; 618 } 619 620 void 621 umcs_break(struct umcs_softc *sc, int portno, int onoff) 622 { 623 uint8_t lcr = sc->sc_subdevs[portno].lcr; 624 625 if (onoff) 626 lcr |= UMCS_LCR_BREAK; 627 else 628 lcr &= ~UMCS_LCR_BREAK; 629 630 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr)) 631 return; 632 sc->sc_subdevs[portno].lcr = lcr; 633 } 634 635 int 636 umcs_open(void *self, int portno) 637 { 638 struct umcs_softc *sc = self; 639 int pn = sc->sc_subdevs[portno].pn; 640 int spreg = umcs_reg_sp(pn); 641 int ctrlreg = umcs_reg_ctrl(pn); 642 uint8_t mcr = sc->sc_subdevs[portno].mcr; 643 uint8_t lcr = sc->sc_subdevs[portno].lcr; 644 uint8_t data; 645 int error; 646 647 if (usbd_is_dying(sc->sc_udev)) 648 return (EIO); 649 650 /* If it very first open, finish global configuration */ 651 if (!sc->sc_init_done) { 652 if (umcs_get_reg(sc, UMCS_CTRL1, &data) || 653 umcs_set_reg(sc, UMCS_CTRL1, data | UMCS_CTRL1_DRIVER_DONE)) 654 return (EIO); 655 sc->sc_init_done = 1; 656 } 657 658 /* Toggle reset bit on-off */ 659 if (umcs_get_reg(sc, spreg, &data) || 660 umcs_set_reg(sc, spreg, data | UMCS_SPx_UART_RESET) || 661 umcs_set_reg(sc, spreg, data & ~UMCS_SPx_UART_RESET)) 662 return (EIO); 663 664 /* Set RS-232 mode */ 665 if (umcs_set_uart_reg(sc, portno, UMCS_REG_SCRATCHPAD, 666 UMCS_SCRATCHPAD_RS232)) 667 return (EIO); 668 669 /* Disable RX on time of initialization */ 670 if (umcs_get_reg(sc, ctrlreg, &data) || 671 umcs_set_reg(sc, ctrlreg, data | UMCS_CTRL_RX_DISABLE)) 672 return (EIO); 673 674 /* Disable all interrupts */ 675 if (umcs_set_uart_reg(sc, portno, UMCS_REG_IER, 0)) 676 return (EIO); 677 678 /* Reset FIFO -- documented */ 679 if (umcs_set_uart_reg(sc, portno, UMCS_REG_FCR, 0) || 680 umcs_set_uart_reg(sc, portno, UMCS_REG_FCR, 681 UMCS_FCR_ENABLE | UMCS_FCR_FLUSHRHR | 682 UMCS_FCR_FLUSHTHR | UMCS_FCR_RTL_1_14)) 683 return (EIO); 684 685 /* Set 8 bit, no parity, 1 stop bit -- documented */ 686 lcr = UMCS_LCR_DATALEN8 | UMCS_LCR_STOPB1; 687 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr)) 688 return (EIO); 689 sc->sc_subdevs[portno].lcr = lcr; 690 691 /* 692 * Enable DTR/RTS on modem control, enable modem interrupts -- 693 * documented 694 */ 695 mcr = UMCS_MCR_DTR | UMCS_MCR_RTS | UMCS_MCR_IE; 696 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr)) 697 return (EIO); 698 sc->sc_subdevs[portno].mcr = mcr; 699 700 /* Clearing Bulkin and Bulkout FIFO */ 701 if (umcs_get_reg(sc, spreg, &data)) 702 return (EIO); 703 data |= UMCS_SPx_RESET_OUT_FIFO|UMCS_SPx_RESET_IN_FIFO; 704 if (umcs_set_reg(sc, spreg, data)) 705 return (EIO); 706 data &= ~(UMCS_SPx_RESET_OUT_FIFO|UMCS_SPx_RESET_IN_FIFO); 707 if (umcs_set_reg(sc, spreg, data)) 708 return (EIO); 709 710 /* Set speed 9600 */ 711 if ((error = umcs_set_baudrate(sc, portno, 9600)) != 0) 712 return (error); 713 714 /* Finally enable all interrupts -- documented */ 715 /* 716 * Copied from vendor driver, I don't know why we should read LCR 717 * here 718 */ 719 if (umcs_get_uart_reg(sc, portno, UMCS_REG_LCR, 720 &sc->sc_subdevs[portno].lcr)) 721 return (EIO); 722 if (umcs_set_uart_reg(sc, portno, UMCS_REG_IER, 723 UMCS_IER_RXSTAT | UMCS_IER_MODEM)) 724 return (EIO); 725 726 /* Enable RX */ 727 if (umcs_get_reg(sc, ctrlreg, &data) || 728 umcs_set_reg(sc, ctrlreg, data & ~UMCS_CTRL_RX_DISABLE)) 729 return (EIO); 730 731 return (0); 732 } 733 734 void 735 umcs_close(void *self, int portno) 736 { 737 struct umcs_softc *sc = self; 738 int pn = sc->sc_subdevs[portno].pn; 739 int ctrlreg = umcs_reg_ctrl(pn); 740 uint8_t data; 741 742 if (usbd_is_dying(sc->sc_udev)) 743 return; 744 745 umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, 0); 746 umcs_set_uart_reg(sc, portno, UMCS_REG_IER, 0); 747 748 /* Disable RX */ 749 if (umcs_get_reg(sc, ctrlreg, &data) || 750 umcs_set_reg(sc, ctrlreg, data | UMCS_CTRL_RX_DISABLE)) 751 return; 752 } 753 754 void 755 umcs_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 756 { 757 struct umcs_softc *sc = priv; 758 uint8_t *buf = sc->sc_ibuf; 759 int actlen, i; 760 761 if (usbd_is_dying(sc->sc_udev)) 762 return; 763 764 if (status == USBD_CANCELLED || status == USBD_IOERROR) 765 return; 766 767 if (status != USBD_NORMAL_COMPLETION) { 768 DPRINTF("%s: interrupt status=%d\n", DEVNAME(sc), status); 769 usbd_clear_endpoint_stall_async(sc->sc_ipipe); 770 return; 771 } 772 773 usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL); 774 if (actlen != 5 && actlen != 13) { 775 printf("%s: invalid interrupt data length %d\n", DEVNAME(sc), 776 actlen); 777 return; 778 } 779 780 /* Check status of all ports */ 781 for (i = 0; i < sc->sc_numports; i++) { 782 uint8_t pn = sc->sc_subdevs[i].pn; 783 784 if (buf[pn] & UMCS_ISR_NOPENDING) 785 continue; 786 787 DPRINTF("%s: port %d has pending interrupt: %02x, FIFO=%02x\n", 788 DEVNAME(sc), i, buf[pn] & UMCS_ISR_INTMASK, 789 buf[pn] & (~UMCS_ISR_INTMASK)); 790 791 switch (buf[pn] & UMCS_ISR_INTMASK) { 792 case UMCS_ISR_RXERR: 793 case UMCS_ISR_RXHASDATA: 794 case UMCS_ISR_RXTIMEOUT: 795 case UMCS_ISR_MSCHANGE: 796 sc->sc_subdevs[i].flags |= UMCS_STATCHG; 797 task_add(systq, &sc->sc_status_task); 798 break; 799 default: 800 /* Do nothing */ 801 break; 802 } 803 } 804 } 805 806 void 807 umcs_status_task(void *arg) 808 { 809 struct umcs_softc *sc = arg; 810 int i; 811 812 for (i = 0; i < sc->sc_numports; i++) { 813 if ((sc->sc_subdevs[i].flags & UMCS_STATCHG) == 0) 814 continue; 815 816 sc->sc_subdevs[i].flags &= ~UMCS_STATCHG; 817 ucom_status_change(sc->sc_subdevs[i].ucom); 818 } 819 } 820