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