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