uvscom.c revision 1.42
1/* $OpenBSD: uvscom.c,v 1.42 2022/07/02 08:50:42 visa Exp $ */ 2/* $NetBSD: uvscom.c,v 1.9 2003/02/12 15:36:20 ichiro Exp $ */ 3/*- 4 * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/dev/usb/uvscom.c,v 1.1 2002/03/18 18:23:39 joe Exp $ 29 */ 30 31/* 32 * uvscom: SUNTAC Slipper U VS-10U driver. 33 * Slipper U is a PC card to USB converter for data communication card 34 * adapter. It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in, 35 * P-in m@ater and various data communication card adapters. 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/malloc.h> 42#include <sys/fcntl.h> 43#include <sys/conf.h> 44#include <sys/tty.h> 45#include <sys/ioctl.h> 46#include <sys/device.h> 47 48#include <dev/usb/usb.h> 49#include <dev/usb/usbcdc.h> 50 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#ifdef UVSCOM_DEBUG 58static int uvscomdebug = 1; 59 60#define DPRINTFN(n, x) do { if (uvscomdebug > (n)) printf x; } while (0) 61#else 62#define DPRINTFN(n, x) 63#endif 64#define DPRINTF(x) DPRINTFN(0, x) 65 66#define UVSCOM_IFACE_INDEX 0 67 68#define UVSCOM_INTR_INTERVAL 100 /* mS */ 69 70#define UVSCOM_UNIT_WAIT 5 71 72/* Request */ 73#define UVSCOM_SET_SPEED 0x10 74#define UVSCOM_LINE_CTL 0x11 75#define UVSCOM_SET_PARAM 0x12 76#define UVSCOM_READ_STATUS 0xd0 77#define UVSCOM_SHUTDOWN 0xe0 78 79/* UVSCOM_SET_SPEED parameters */ 80#define UVSCOM_SPEED_150BPS 0x00 81#define UVSCOM_SPEED_300BPS 0x01 82#define UVSCOM_SPEED_600BPS 0x02 83#define UVSCOM_SPEED_1200BPS 0x03 84#define UVSCOM_SPEED_2400BPS 0x04 85#define UVSCOM_SPEED_4800BPS 0x05 86#define UVSCOM_SPEED_9600BPS 0x06 87#define UVSCOM_SPEED_19200BPS 0x07 88#define UVSCOM_SPEED_38400BPS 0x08 89#define UVSCOM_SPEED_57600BPS 0x09 90#define UVSCOM_SPEED_115200BPS 0x0a 91 92/* UVSCOM_LINE_CTL parameters */ 93#define UVSCOM_BREAK 0x40 94#define UVSCOM_RTS 0x02 95#define UVSCOM_DTR 0x01 96#define UVSCOM_LINE_INIT 0x08 97 98/* UVSCOM_SET_PARAM parameters */ 99#define UVSCOM_DATA_MASK 0x03 100#define UVSCOM_DATA_BIT_8 0x03 101#define UVSCOM_DATA_BIT_7 0x02 102#define UVSCOM_DATA_BIT_6 0x01 103#define UVSCOM_DATA_BIT_5 0x00 104 105#define UVSCOM_STOP_MASK 0x04 106#define UVSCOM_STOP_BIT_2 0x04 107#define UVSCOM_STOP_BIT_1 0x00 108 109#define UVSCOM_PARITY_MASK 0x18 110#define UVSCOM_PARITY_EVEN 0x18 111#if 0 112#define UVSCOM_PARITY_UNK 0x10 113#endif 114#define UVSCOM_PARITY_ODD 0x08 115#define UVSCOM_PARITY_NONE 0x00 116 117/* Status bits */ 118#define UVSCOM_TXRDY 0x04 119#define UVSCOM_RXRDY 0x01 120 121#define UVSCOM_DCD 0x08 122#define UVSCOM_NOCARD 0x04 123#define UVSCOM_DSR 0x02 124#define UVSCOM_CTS 0x01 125#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS) 126 127struct uvscom_softc { 128 struct device sc_dev; /* base device */ 129 struct usbd_device *sc_udev; /* USB device */ 130 struct usbd_interface *sc_iface; /* interface */ 131 132 struct usbd_interface *sc_intr_iface; /* interrupt interface */ 133 int sc_intr_number; /* interrupt number */ 134 struct usbd_pipe *sc_intr_pipe; /* interrupt pipe */ 135 u_char *sc_intr_buf; /* interrupt buffer */ 136 int sc_isize; 137 138 u_char sc_dtr; /* current DTR state */ 139 u_char sc_rts; /* current RTS state */ 140 141 u_char sc_lsr; /* Local status register */ 142 u_char sc_msr; /* uvscom status register */ 143 144 uint16_t sc_lcr; /* Line control */ 145 u_char sc_usr; /* unit status */ 146 147 struct device *sc_subdev; /* ucom device */ 148}; 149 150/* 151 * These are the maximum number of bytes transferred per frame. 152 * The output buffer size cannot be increased due to the size encoding. 153 */ 154#define UVSCOMIBUFSIZE 512 155#define UVSCOMOBUFSIZE 64 156 157usbd_status uvscom_readstat(struct uvscom_softc *); 158usbd_status uvscom_shutdown(struct uvscom_softc *); 159usbd_status uvscom_reset(struct uvscom_softc *); 160usbd_status uvscom_set_line_coding(struct uvscom_softc *, 161 uint16_t, uint16_t); 162usbd_status uvscom_set_line(struct uvscom_softc *, uint16_t); 163usbd_status uvscom_set_crtscts(struct uvscom_softc *); 164void uvscom_get_status(void *, int, u_char *, u_char *); 165void uvscom_dtr(struct uvscom_softc *, int); 166void uvscom_rts(struct uvscom_softc *, int); 167void uvscom_break(struct uvscom_softc *, int); 168 169void uvscom_set(void *, int, int, int); 170void uvscom_intr(struct usbd_xfer *, void *, usbd_status); 171int uvscom_param(void *, int, struct termios *); 172int uvscom_open(void *, int); 173void uvscom_close(void *, int); 174 175const struct ucom_methods uvscom_methods = { 176 uvscom_get_status, 177 uvscom_set, 178 uvscom_param, 179 NULL, /* uvscom_ioctl, TODO */ 180 uvscom_open, 181 uvscom_close, 182 NULL, 183 NULL 184}; 185 186static const struct usb_devno uvscom_devs [] = { 187 /* SUNTAC U-Cable type A3 */ 188 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS64LX }, 189 /* SUNTAC U-Cable type A4 */ 190 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4 }, 191 /* SUNTAC U-Cable type D2 */ 192 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L }, 193 /* SUNTAC U-Cable type P1 */ 194 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1 }, 195 /* SUNTAC Slipper U */ 196 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U }, 197 /* SUNTAC Ir-Trinity */ 198 { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U }, 199}; 200 201int uvscom_match(struct device *, void *, void *); 202void uvscom_attach(struct device *, struct device *, void *); 203int uvscom_detach(struct device *, int); 204 205struct cfdriver uvscom_cd = { 206 NULL, "uvscom", DV_DULL 207}; 208 209const struct cfattach uvscom_ca = { 210 sizeof(struct uvscom_softc), uvscom_match, uvscom_attach, uvscom_detach 211}; 212 213int 214uvscom_match(struct device *parent, void *match, void *aux) 215{ 216 struct usb_attach_arg *uaa = aux; 217 218 if (uaa->iface == NULL) 219 return (UMATCH_NONE); 220 221 return (usb_lookup(uvscom_devs, uaa->vendor, uaa->product) != NULL ? 222 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 223} 224 225void 226uvscom_attach(struct device *parent, struct device *self, void *aux) 227{ 228 struct uvscom_softc *sc = (struct uvscom_softc *)self; 229 struct usb_attach_arg *uaa = aux; 230 struct usbd_device *dev = uaa->device; 231 usb_config_descriptor_t *cdesc; 232 usb_interface_descriptor_t *id; 233 usb_endpoint_descriptor_t *ed; 234 const char *devname = sc->sc_dev.dv_xname; 235 usbd_status err; 236 int i; 237 struct ucom_attach_args uca; 238 239 sc->sc_udev = dev; 240 241 DPRINTF(("uvscom attach: sc = %p\n", sc)); 242 243 /* initialize endpoints */ 244 uca.bulkin = uca.bulkout = -1; 245 sc->sc_intr_number = -1; 246 sc->sc_intr_pipe = NULL; 247 248 /* get the config descriptor */ 249 cdesc = usbd_get_config_descriptor(sc->sc_udev); 250 251 if (cdesc == NULL) { 252 printf("%s: failed to get configuration descriptor\n", 253 sc->sc_dev.dv_xname); 254 usbd_deactivate(sc->sc_udev); 255 return; 256 } 257 258 /* get the common interface */ 259 err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX, 260 &sc->sc_iface); 261 if (err) { 262 printf("%s: failed to get interface, err=%s\n", 263 devname, usbd_errstr(err)); 264 usbd_deactivate(sc->sc_udev); 265 return; 266 } 267 268 id = usbd_get_interface_descriptor(sc->sc_iface); 269 270 /* Find endpoints */ 271 for (i = 0; i < id->bNumEndpoints; i++) { 272 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 273 if (ed == NULL) { 274 printf("%s: no endpoint descriptor for %d\n", 275 sc->sc_dev.dv_xname, i); 276 usbd_deactivate(sc->sc_udev); 277 return; 278 } 279 280 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 281 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 282 uca.bulkin = ed->bEndpointAddress; 283 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 284 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 285 uca.bulkout = ed->bEndpointAddress; 286 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 287 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 288 sc->sc_intr_number = ed->bEndpointAddress; 289 sc->sc_isize = UGETW(ed->wMaxPacketSize); 290 } 291 } 292 293 if (uca.bulkin == -1) { 294 printf("%s: Could not find data bulk in\n", 295 sc->sc_dev.dv_xname); 296 usbd_deactivate(sc->sc_udev); 297 return; 298 } 299 if (uca.bulkout == -1) { 300 printf("%s: Could not find data bulk out\n", 301 sc->sc_dev.dv_xname); 302 usbd_deactivate(sc->sc_udev); 303 return; 304 } 305 if (sc->sc_intr_number == -1) { 306 printf("%s: Could not find interrupt in\n", 307 sc->sc_dev.dv_xname); 308 usbd_deactivate(sc->sc_udev); 309 return; 310 } 311 312 sc->sc_dtr = sc->sc_rts = 0; 313 sc->sc_lcr = UVSCOM_LINE_INIT; 314 315 uca.portno = UCOM_UNK_PORTNO; 316 /* bulkin, bulkout set above */ 317 uca.ibufsize = UVSCOMIBUFSIZE; 318 uca.obufsize = UVSCOMOBUFSIZE; 319 uca.ibufsizepad = UVSCOMIBUFSIZE; 320 uca.opkthdrlen = 0; 321 uca.device = dev; 322 uca.iface = sc->sc_iface; 323 uca.methods = &uvscom_methods; 324 uca.arg = sc; 325 uca.info = NULL; 326 327 err = uvscom_reset(sc); 328 329 if (err) { 330 printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname, 331 usbd_errstr(err)); 332 usbd_deactivate(sc->sc_udev); 333 return; 334 } 335 336 DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n", 337 ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number)); 338 339 DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n", 340 uca.bulkin, uca.bulkout, sc->sc_intr_number )); 341 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 342} 343 344int 345uvscom_detach(struct device *self, int flags) 346{ 347 struct uvscom_softc *sc = (struct uvscom_softc *)self; 348 int rv = 0; 349 350 DPRINTF(("uvscom_detach: sc = %p\n", sc)); 351 352 if (sc->sc_intr_pipe != NULL) { 353 usbd_close_pipe(sc->sc_intr_pipe); 354 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize); 355 sc->sc_intr_pipe = NULL; 356 } 357 358 if (sc->sc_subdev != NULL) { 359 rv = config_detach(sc->sc_subdev, flags); 360 sc->sc_subdev = NULL; 361 } 362 363 return (rv); 364} 365 366usbd_status 367uvscom_readstat(struct uvscom_softc *sc) 368{ 369 usb_device_request_t req; 370 usbd_status err; 371 uint16_t r; 372 373 DPRINTF(("%s: send readstat\n", sc->sc_dev.dv_xname)); 374 375 req.bmRequestType = UT_READ_VENDOR_DEVICE; 376 req.bRequest = UVSCOM_READ_STATUS; 377 USETW(req.wValue, 0); 378 USETW(req.wIndex, 0); 379 USETW(req.wLength, 2); 380 381 err = usbd_do_request(sc->sc_udev, &req, &r); 382 if (err) { 383 printf("%s: uvscom_readstat: %s\n", 384 sc->sc_dev.dv_xname, usbd_errstr(err)); 385 return (err); 386 } 387 388 DPRINTF(("%s: uvscom_readstat: r = %d\n", 389 sc->sc_dev.dv_xname, r)); 390 391 return (USBD_NORMAL_COMPLETION); 392} 393 394usbd_status 395uvscom_shutdown(struct uvscom_softc *sc) 396{ 397 usb_device_request_t req; 398 usbd_status err; 399 400 DPRINTF(("%s: send shutdown\n", sc->sc_dev.dv_xname)); 401 402 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 403 req.bRequest = UVSCOM_SHUTDOWN; 404 USETW(req.wValue, 0); 405 USETW(req.wIndex, 0); 406 USETW(req.wLength, 0); 407 408 err = usbd_do_request(sc->sc_udev, &req, NULL); 409 if (err) { 410 printf("%s: uvscom_shutdown: %s\n", 411 sc->sc_dev.dv_xname, usbd_errstr(err)); 412 return (err); 413 } 414 415 return (USBD_NORMAL_COMPLETION); 416} 417 418usbd_status 419uvscom_reset(struct uvscom_softc *sc) 420{ 421 DPRINTF(("%s: uvscom_reset\n", sc->sc_dev.dv_xname)); 422 423 return (USBD_NORMAL_COMPLETION); 424} 425 426usbd_status 427uvscom_set_crtscts(struct uvscom_softc *sc) 428{ 429 DPRINTF(("%s: uvscom_set_crtscts\n", sc->sc_dev.dv_xname)); 430 431 return (USBD_NORMAL_COMPLETION); 432} 433 434usbd_status 435uvscom_set_line(struct uvscom_softc *sc, uint16_t line) 436{ 437 usb_device_request_t req; 438 usbd_status err; 439 440 DPRINTF(("%s: uvscom_set_line: %04x\n", 441 sc->sc_dev.dv_xname, line)); 442 443 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 444 req.bRequest = UVSCOM_LINE_CTL; 445 USETW(req.wValue, line); 446 USETW(req.wIndex, 0); 447 USETW(req.wLength, 0); 448 449 err = usbd_do_request(sc->sc_udev, &req, NULL); 450 if (err) { 451 printf("%s: uvscom_set_line: %s\n", 452 sc->sc_dev.dv_xname, usbd_errstr(err)); 453 return (err); 454 } 455 456 return (USBD_NORMAL_COMPLETION); 457} 458 459usbd_status 460uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls) 461{ 462 usb_device_request_t req; 463 usbd_status err; 464 465 DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n", 466 sc->sc_dev.dv_xname, lsp, ls)); 467 468 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 469 req.bRequest = UVSCOM_SET_SPEED; 470 USETW(req.wValue, lsp); 471 USETW(req.wIndex, 0); 472 USETW(req.wLength, 0); 473 474 err = usbd_do_request(sc->sc_udev, &req, NULL); 475 if (err) { 476 printf("%s: uvscom_set_line_coding: %s\n", 477 sc->sc_dev.dv_xname, usbd_errstr(err)); 478 return (err); 479 } 480 481 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 482 req.bRequest = UVSCOM_SET_PARAM; 483 USETW(req.wValue, ls); 484 USETW(req.wIndex, 0); 485 USETW(req.wLength, 0); 486 487 err = usbd_do_request(sc->sc_udev, &req, NULL); 488 if (err) { 489 printf("%s: uvscom_set_line_coding: %s\n", 490 sc->sc_dev.dv_xname, usbd_errstr(err)); 491 return (err); 492 } 493 494 return (USBD_NORMAL_COMPLETION); 495} 496 497void 498uvscom_dtr(struct uvscom_softc *sc, int onoff) 499{ 500 DPRINTF(("%s: uvscom_dtr: onoff = %d\n", 501 sc->sc_dev.dv_xname, onoff)); 502 503 if (sc->sc_dtr == onoff) 504 return; /* no change */ 505 506 sc->sc_dtr = onoff; 507 508 if (onoff) 509 SET(sc->sc_lcr, UVSCOM_DTR); 510 else 511 CLR(sc->sc_lcr, UVSCOM_DTR); 512 513 uvscom_set_line(sc, sc->sc_lcr); 514} 515 516void 517uvscom_rts(struct uvscom_softc *sc, int onoff) 518{ 519 DPRINTF(("%s: uvscom_rts: onoff = %d\n", 520 sc->sc_dev.dv_xname, onoff)); 521 522 if (sc->sc_rts == onoff) 523 return; /* no change */ 524 525 sc->sc_rts = onoff; 526 527 if (onoff) 528 SET(sc->sc_lcr, UVSCOM_RTS); 529 else 530 CLR(sc->sc_lcr, UVSCOM_RTS); 531 532 uvscom_set_line(sc, sc->sc_lcr); 533} 534 535void 536uvscom_break(struct uvscom_softc *sc, int onoff) 537{ 538 DPRINTF(("%s: uvscom_break: onoff = %d\n", 539 sc->sc_dev.dv_xname, onoff)); 540 541 if (onoff) 542 uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK)); 543} 544 545void 546uvscom_set(void *addr, int portno, int reg, int onoff) 547{ 548 struct uvscom_softc *sc = addr; 549 550 switch (reg) { 551 case UCOM_SET_DTR: 552 uvscom_dtr(sc, onoff); 553 break; 554 case UCOM_SET_RTS: 555 uvscom_rts(sc, onoff); 556 break; 557 case UCOM_SET_BREAK: 558 uvscom_break(sc, onoff); 559 break; 560 default: 561 break; 562 } 563} 564 565int 566uvscom_param(void *addr, int portno, struct termios *t) 567{ 568 struct uvscom_softc *sc = addr; 569 usbd_status err; 570 uint16_t lsp; 571 uint16_t ls; 572 573 DPRINTF(("%s: uvscom_param: sc = %p\n", 574 sc->sc_dev.dv_xname, sc)); 575 576 ls = 0; 577 578 switch (t->c_ospeed) { 579 case B150: 580 lsp = UVSCOM_SPEED_150BPS; 581 break; 582 case B300: 583 lsp = UVSCOM_SPEED_300BPS; 584 break; 585 case B600: 586 lsp = UVSCOM_SPEED_600BPS; 587 break; 588 case B1200: 589 lsp = UVSCOM_SPEED_1200BPS; 590 break; 591 case B2400: 592 lsp = UVSCOM_SPEED_2400BPS; 593 break; 594 case B4800: 595 lsp = UVSCOM_SPEED_4800BPS; 596 break; 597 case B9600: 598 lsp = UVSCOM_SPEED_9600BPS; 599 break; 600 case B19200: 601 lsp = UVSCOM_SPEED_19200BPS; 602 break; 603 case B38400: 604 lsp = UVSCOM_SPEED_38400BPS; 605 break; 606 case B57600: 607 lsp = UVSCOM_SPEED_57600BPS; 608 break; 609 case B115200: 610 lsp = UVSCOM_SPEED_115200BPS; 611 break; 612 default: 613 return (EIO); 614 } 615 616 if (ISSET(t->c_cflag, CSTOPB)) 617 SET(ls, UVSCOM_STOP_BIT_2); 618 else 619 SET(ls, UVSCOM_STOP_BIT_1); 620 621 if (ISSET(t->c_cflag, PARENB)) { 622 if (ISSET(t->c_cflag, PARODD)) 623 SET(ls, UVSCOM_PARITY_ODD); 624 else 625 SET(ls, UVSCOM_PARITY_EVEN); 626 } else 627 SET(ls, UVSCOM_PARITY_NONE); 628 629 switch (ISSET(t->c_cflag, CSIZE)) { 630 case CS5: 631 SET(ls, UVSCOM_DATA_BIT_5); 632 break; 633 case CS6: 634 SET(ls, UVSCOM_DATA_BIT_6); 635 break; 636 case CS7: 637 SET(ls, UVSCOM_DATA_BIT_7); 638 break; 639 case CS8: 640 SET(ls, UVSCOM_DATA_BIT_8); 641 break; 642 default: 643 return (EIO); 644 } 645 646 err = uvscom_set_line_coding(sc, lsp, ls); 647 if (err) 648 return (EIO); 649 650 if (ISSET(t->c_cflag, CRTSCTS)) { 651 err = uvscom_set_crtscts(sc); 652 if (err) 653 return (EIO); 654 } 655 656 return (0); 657} 658 659int 660uvscom_open(void *addr, int portno) 661{ 662 struct uvscom_softc *sc = addr; 663 int err; 664 int i; 665 666 if (usbd_is_dying(sc->sc_udev)) 667 return (EIO); 668 669 DPRINTF(("uvscom_open: sc = %p\n", sc)); 670 671 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 672 DPRINTF(("uvscom_open: open interrupt pipe.\n")); 673 674 sc->sc_usr = 0; /* clear unit status */ 675 676 err = uvscom_readstat(sc); 677 if (err) { 678 DPRINTF(("%s: uvscom_open: readstat failed\n", 679 sc->sc_dev.dv_xname)); 680 return (EIO); 681 } 682 683 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 684 err = usbd_open_pipe_intr(sc->sc_iface, 685 sc->sc_intr_number, 686 USBD_SHORT_XFER_OK, 687 &sc->sc_intr_pipe, 688 sc, 689 sc->sc_intr_buf, 690 sc->sc_isize, 691 uvscom_intr, 692 UVSCOM_INTR_INTERVAL); 693 if (err) { 694 printf("%s: cannot open interrupt pipe (addr %d)\n", 695 sc->sc_dev.dv_xname, 696 sc->sc_intr_number); 697 return (EIO); 698 } 699 } else { 700 DPRINTF(("uvscom_open: did not open interrupt pipe.\n")); 701 } 702 703 if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) { 704 /* unit is not ready */ 705 706 for (i = UVSCOM_UNIT_WAIT; i > 0; --i) { 707 tsleep_nsec(&err, TTIPRI, "uvsop", SEC_TO_NSEC(1)); 708 if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK)) 709 break; 710 } 711 if (i == 0) { 712 DPRINTF(("%s: unit is not ready\n", 713 sc->sc_dev.dv_xname)); 714 return (EIO); 715 } 716 717 /* check PC card was inserted */ 718 if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) { 719 DPRINTF(("%s: no card\n", 720 sc->sc_dev.dv_xname)); 721 return (EIO); 722 } 723 } 724 725 return (0); 726} 727 728void 729uvscom_close(void *addr, int portno) 730{ 731 struct uvscom_softc *sc = addr; 732 int err; 733 734 if (usbd_is_dying(sc->sc_udev)) 735 return; 736 737 DPRINTF(("uvscom_close: close\n")); 738 739 uvscom_shutdown(sc); 740 741 if (sc->sc_intr_pipe != NULL) { 742 err = usbd_close_pipe(sc->sc_intr_pipe); 743 if (err) 744 printf("%s: close interrupt pipe failed: %s\n", 745 sc->sc_dev.dv_xname, 746 usbd_errstr(err)); 747 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize); 748 sc->sc_intr_pipe = NULL; 749 } 750} 751 752void 753uvscom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 754{ 755 struct uvscom_softc *sc = priv; 756 u_char *buf = sc->sc_intr_buf; 757 u_char pstatus; 758 759 if (usbd_is_dying(sc->sc_udev)) 760 return; 761 762 if (status != USBD_NORMAL_COMPLETION) { 763 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 764 return; 765 766 printf("%s: uvscom_intr: abnormal status: %s\n", 767 sc->sc_dev.dv_xname, 768 usbd_errstr(status)); 769 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 770 return; 771 } 772 773 DPRINTFN(2, ("%s: uvscom status = %02x %02x\n", 774 sc->sc_dev.dv_xname, buf[0], buf[1])); 775 776 sc->sc_lsr = sc->sc_msr = 0; 777 sc->sc_usr = buf[1]; 778 779 pstatus = buf[0]; 780 if (ISSET(pstatus, UVSCOM_TXRDY)) 781 SET(sc->sc_lsr, ULSR_TXRDY); 782 if (ISSET(pstatus, UVSCOM_RXRDY)) 783 SET(sc->sc_lsr, ULSR_RXRDY); 784 785 pstatus = buf[1]; 786 if (ISSET(pstatus, UVSCOM_CTS)) 787 SET(sc->sc_msr, UMSR_CTS); 788 if (ISSET(pstatus, UVSCOM_DSR)) 789 SET(sc->sc_msr, UMSR_DSR); 790 if (ISSET(pstatus, UVSCOM_DCD)) 791 SET(sc->sc_msr, UMSR_DCD); 792 793 ucom_status_change((struct ucom_softc *) sc->sc_subdev); 794} 795 796void 797uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 798{ 799 struct uvscom_softc *sc = addr; 800 801 if (lsr != NULL) 802 *lsr = sc->sc_lsr; 803 if (msr != NULL) 804 *msr = sc->sc_msr; 805} 806