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