uplcom.c revision 1.16 1 /* $NetBSD: uplcom.c,v 1.16 2001/04/02 13:38:14 ichiro Exp $ */
2 /*
3 * Copyright (c) 2001 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Ichiro FUKUHARA (ichiro (at) ichiro.org).
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 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Simple datasheet
40 * http://www.prolific.com.tw/download/DataSheet/pl2303_ds11.PDF
41 * http://www.nisseisg.co.jp/jyouhou/_cp/@gif/2303.pdf
42 * (english)
43 *
44 */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/ioctl.h>
51 #include <sys/conf.h>
52 #include <sys/tty.h>
53 #include <sys/file.h>
54 #include <sys/select.h>
55 #include <sys/proc.h>
56 #include <sys/vnode.h>
57 #include <sys/device.h>
58 #include <sys/poll.h>
59
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbcdc.h>
62
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdi_util.h>
65 #include <dev/usb/usbdevs.h>
66 #include <dev/usb/usb_quirks.h>
67
68 #include <dev/usb/usbdevs.h>
69 #include <dev/usb/ucomvar.h>
70
71 #ifdef UPLCOM_DEBUG
72 #define DPRINTFN(n, x) if (uplcomdebug > (n)) logprintf x
73 int uplcomdebug = 0;
74 #else
75 #define DPRINTFN(n, x)
76 #endif
77 #define DPRINTF(x) DPRINTFN(0, x)
78
79 #define UPLCOM_CONFIG_INDEX 0
80 #define UPLCOM_IFACE_INDEX 0
81 #define UPLCOM_SECOND_IFACE_INDEX 1
82 #define UPLCOM_RESET 0
83
84 #define RSAQ_STATUS_DSR 0x02
85 #define RSAQ_STATUS_DCD 0x01
86
87 struct uplcom_softc {
88 USBBASEDEVICE sc_dev; /* base device */
89 usbd_device_handle sc_udev; /* USB device */
90 usbd_interface_handle sc_iface; /* interface */
91 int sc_iface_number; /* interface number */
92
93 int sc_intr_number; /* interrupt number */
94 usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
95 u_char *sc_intr_buf; /* interrupt buffer */
96 int sc_isize;
97
98 usb_cdc_line_state_t sc_line_state; /* current line state */
99 u_char sc_dtr; /* current DTR state */
100 u_char sc_rts; /* current RTS state */
101 u_char sc_status;
102
103 device_ptr_t sc_subdev; /* ucom device */
104
105 u_char sc_dying; /* disconnecting */
106
107 u_char sc_lsr; /* Local status register */
108 u_char sc_msr; /* uplcom status register */
109 };
110
111 /*
112 * These are the maximum number of bytes transferred per frame.
113 * The output buffer size cannot be increased due to the size encoding.
114 */
115 #define UPLCOMIBUFSIZE 256
116 #define UPLCOMOBUFSIZE 256
117
118 Static usbd_status uplcom_reset(struct uplcom_softc *);
119 Static usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
120 usb_cdc_line_state_t *state);
121 Static void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
122
123 Static void uplcom_set(void *, int, int, int);
124 Static void uplcom_dtr(struct uplcom_softc *, int);
125 Static void uplcom_rts(struct uplcom_softc *, int);
126 Static void uplcom_break(struct uplcom_softc *, int);
127 Static void uplcom_set_line_state(struct uplcom_softc *);
128 Static void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
129 #if TODO
130 Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, struct proc *);
131 #endif
132 Static int uplcom_param(void *, int, struct termios *);
133 Static int uplcom_open(void *, int);
134 Static void uplcom_close(void *, int);
135
136 struct ucom_methods uplcom_methods = {
137 uplcom_get_status,
138 uplcom_set,
139 uplcom_param,
140 NULL, /* uplcom_ioctl, TODO */
141 uplcom_open,
142 uplcom_close,
143 NULL,
144 NULL,
145 };
146
147 static const struct uplcom_product {
148 uint16_t vendor;
149 uint16_t product;
150 } uplcom_products [] = {
151 /* I/O DATA USB-RSAQ2 */
152 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
153 /* I/O DATA USB-RSAQ */
154 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
155 /* PLANEX USB-RS232 URS-03 */
156 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
157
158 { 0, 0 }
159 };
160
161 USB_DECLARE_DRIVER(uplcom);
162
163 USB_MATCH(uplcom)
164 {
165 USB_MATCH_START(uplcom, uaa);
166 int i;
167
168 if (uaa->iface != NULL)
169 return (UMATCH_NONE);
170
171 for (i = 0; uplcom_products[i].vendor != 0; i++) {
172 if (uplcom_products[i].vendor == uaa->vendor &&
173 uplcom_products[i].product == uaa->product) {
174 return (UMATCH_VENDOR_PRODUCT);
175 }
176 }
177 return (UMATCH_NONE);
178 }
179
180 USB_ATTACH(uplcom)
181 {
182 USB_ATTACH_START(uplcom, sc, uaa);
183 usbd_device_handle dev = uaa->device;
184 usb_config_descriptor_t *cdesc;
185 usb_interface_descriptor_t *id;
186 usb_endpoint_descriptor_t *ed;
187
188 char devinfo[1024];
189 char *devname = USBDEVNAME(sc->sc_dev);
190 usbd_status err;
191 int i;
192 struct ucom_attach_args uca;
193
194 usbd_devinfo(dev, 0, devinfo);
195 USB_ATTACH_SETUP;
196 printf("%s: %s\n", devname, devinfo);
197
198 sc->sc_udev = dev;
199
200 DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
201
202 /* initialize endpoints */
203 uca.bulkin = uca.bulkout = -1;
204 sc->sc_intr_number = -1;
205 sc->sc_intr_pipe = NULL;
206
207 /* Move the device into the configured state. */
208 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
209 if (err) {
210 printf("\n%s: failed to set configuration, err=%s\n",
211 devname, usbd_errstr(err));
212 sc->sc_dying = 1;
213 USB_ATTACH_ERROR_RETURN;
214 }
215
216 /* get the config descriptor */
217 cdesc = usbd_get_config_descriptor(sc->sc_udev);
218
219 if (cdesc == NULL) {
220 printf("%s: failed to get configuration descriptor\n",
221 USBDEVNAME(sc->sc_dev));
222 sc->sc_dying = 1;
223 USB_ATTACH_ERROR_RETURN;
224 }
225
226 /* get the (first/common) interface */
227 err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
228 &sc->sc_iface);
229 if (err) {
230 printf("\n%s: failed to get interface, err=%s\n",
231 devname, usbd_errstr(err));
232 sc->sc_dying = 1;
233 USB_ATTACH_ERROR_RETURN;
234 }
235
236 /* Find the interrupt endpoints */
237
238 id = usbd_get_interface_descriptor(sc->sc_iface);
239 sc->sc_iface_number = id->bInterfaceNumber;
240
241 for (i = 0; i < id->bNumEndpoints; i++) {
242 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
243 if (ed == NULL) {
244 printf("%s: no endpoint descriptor for %d\n",
245 USBDEVNAME(sc->sc_dev), i);
246 sc->sc_dying = 1;
247 USB_ATTACH_ERROR_RETURN;
248 }
249
250 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
251 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
252 sc->sc_intr_number = ed->bEndpointAddress;
253 sc->sc_isize = UGETW(ed->wMaxPacketSize);
254 }
255 }
256
257 if (sc->sc_intr_number== -1) {
258 printf("%s: Could not find interrupt in\n",
259 USBDEVNAME(sc->sc_dev));
260 sc->sc_dying = 1;
261 USB_ATTACH_ERROR_RETURN;
262 }
263
264 /*
265 * USB-RSAQ1 has two interface
266 *
267 * USB-RSAQ1 | USB-RSAQ2
268 * -----------------+-----------------
269 * Interface 0 |Interface 0
270 * Interrupt(0x81) | Interrupt(0x81)
271 * -----------------+ BulkIN(0x02)
272 * Interface 1 | BulkOUT(0x83)
273 * BulkIN(0x02) |
274 * BulkOUT(0x83) |
275 */
276 if (cdesc->bNumInterface == 2) {
277 err = usbd_device2interface_handle(dev,
278 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface);
279 if (err) {
280 printf("\n%s: failed to get second interface, err=%s\n",
281 devname, usbd_errstr(err));
282 sc->sc_dying = 1;
283 USB_ATTACH_ERROR_RETURN;
284 }
285 }
286
287 /* Find the bulk{in,out} endpoints */
288
289 id = usbd_get_interface_descriptor(sc->sc_iface);
290 sc->sc_iface_number = id->bInterfaceNumber;
291
292 for (i = 0; i < id->bNumEndpoints; i++) {
293 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
294 if (ed == NULL) {
295 printf("%s: no endpoint descriptor for %d\n",
296 USBDEVNAME(sc->sc_dev), i);
297 sc->sc_dying = 1;
298 USB_ATTACH_ERROR_RETURN;
299 }
300
301 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
302 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
303 uca.bulkin = ed->bEndpointAddress;
304 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
305 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
306 uca.bulkout = ed->bEndpointAddress;
307 }
308 }
309
310 if (uca.bulkin == -1) {
311 printf("%s: Could not find data bulk in\n",
312 USBDEVNAME(sc->sc_dev));
313 sc->sc_dying = 1;
314 USB_ATTACH_ERROR_RETURN;
315 }
316
317 if (uca.bulkout == -1) {
318 printf("%s: Could not find data bulk out\n",
319 USBDEVNAME(sc->sc_dev));
320 sc->sc_dying = 1;
321 USB_ATTACH_ERROR_RETURN;
322 }
323
324 sc->sc_dtr = sc->sc_rts = -1;
325 uca.portno = UCOM_UNK_PORTNO;
326 /* bulkin, bulkout set above */
327 uca.ibufsize = UPLCOMIBUFSIZE;
328 uca.obufsize = UPLCOMOBUFSIZE;
329 uca.ibufsizepad = UPLCOMIBUFSIZE;
330 uca.opkthdrlen = 0;
331 uca.device = dev;
332 uca.iface = sc->sc_iface;
333 uca.methods = &uplcom_methods;
334 uca.arg = sc;
335 uca.info = NULL;
336
337 err = uplcom_reset(sc);
338
339 if (err) {
340 printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev),
341 usbd_errstr(err));
342 sc->sc_dying = 1;
343 USB_ATTACH_ERROR_RETURN;
344 }
345
346 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
347 USBDEV(sc->sc_dev));
348
349 DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
350 uca.bulkin, uca.bulkout, sc->sc_intr_number ));
351 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
352
353 USB_ATTACH_SUCCESS_RETURN;
354 }
355
356 USB_DETACH(uplcom)
357 {
358 USB_DETACH_START(uplcom, sc);
359 int rv = 0;
360
361 DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
362
363 if (sc->sc_intr_pipe != NULL) {
364 usbd_abort_pipe(sc->sc_intr_pipe);
365 usbd_close_pipe(sc->sc_intr_pipe);
366 free(sc->sc_intr_buf, M_USBDEV);
367 sc->sc_intr_pipe = NULL;
368 }
369
370 sc->sc_dying = 1;
371 if (sc->sc_subdev != NULL) {
372 rv = config_detach(sc->sc_subdev, flags);
373 sc->sc_subdev = NULL;
374 }
375
376 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
377 USBDEV(sc->sc_dev));
378
379 return (rv);
380 }
381
382 int
383 uplcom_activate(device_ptr_t self, enum devact act)
384 {
385 struct uplcom_softc *sc = (struct uplcom_softc *)self;
386 int rv = 0;
387
388 switch (act) {
389 case DVACT_ACTIVATE:
390 return (EOPNOTSUPP);
391 break;
392
393 case DVACT_DEACTIVATE:
394 if (sc->sc_subdev != NULL)
395 rv = config_deactivate(sc->sc_subdev);
396 sc->sc_dying = 1;
397 break;
398 }
399 return (rv);
400 }
401
402
403 usbd_status
404 uplcom_reset(struct uplcom_softc *sc)
405 {
406 usb_device_request_t req;
407 usbd_status err;
408
409 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
410 req.bRequest = UPLCOM_RESET;
411 USETW(req.wValue, UPLCOM_RESET);
412 USETW(req.wIndex, sc->sc_iface_number);
413 USETW(req.wLength, 0);
414
415 err = usbd_do_request(sc->sc_udev, &req, 0);
416 if (err)
417 return (EIO);
418
419 return (0);
420 }
421
422 void
423 uplcom_set_line_state(struct uplcom_softc *sc)
424 {
425 usb_device_request_t req;
426 int ls;
427
428 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
429 (sc->sc_rts ? UCDC_LINE_RTS : 0);
430 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
431 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
432 USETW(req.wValue, ls);
433 USETW(req.wIndex, sc->sc_iface_number);
434 USETW(req.wLength, 0);
435
436 (void)usbd_do_request(sc->sc_udev, &req, 0);
437
438 }
439
440 void
441 uplcom_set(void *addr, int portno, int reg, int onoff)
442 {
443 struct uplcom_softc *sc = addr;
444
445 switch (reg) {
446 case UCOM_SET_DTR:
447 uplcom_dtr(sc, onoff);
448 break;
449 case UCOM_SET_RTS:
450 uplcom_rts(sc, onoff);
451 break;
452 case UCOM_SET_BREAK:
453 uplcom_break(sc, onoff);
454 break;
455 default:
456 break;
457 }
458 }
459
460 void
461 uplcom_dtr(struct uplcom_softc *sc, int onoff)
462 {
463
464 DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
465
466 if (sc->sc_dtr == onoff)
467 return;
468 sc->sc_dtr = onoff;
469
470 uplcom_set_line_state(sc);
471 }
472
473 void
474 uplcom_rts(struct uplcom_softc *sc, int onoff)
475 {
476 DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
477
478 if (sc->sc_rts == onoff)
479 return;
480 sc->sc_rts = onoff;
481
482 uplcom_set_line_state(sc);
483 }
484
485 void
486 uplcom_break(struct uplcom_softc *sc, int onoff)
487 {
488 usb_device_request_t req;
489
490 DPRINTF(("uplcom_break: onoff=%d\n", onoff));
491
492 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
493 req.bRequest = UCDC_SEND_BREAK;
494 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
495 USETW(req.wIndex, sc->sc_iface_number);
496 USETW(req.wLength, 0);
497
498 (void)usbd_do_request(sc->sc_udev, &req, 0);
499 }
500
501 usbd_status
502 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
503 {
504 usb_device_request_t req;
505 usbd_status err;
506
507 DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
508 UGETDW(state->dwDTERate), state->bCharFormat,
509 state->bParityType, state->bDataBits));
510
511 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
512 DPRINTF(("uplcom_set_line_coding: already set\n"));
513 return (USBD_NORMAL_COMPLETION);
514 }
515
516 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
517 req.bRequest = UCDC_SET_LINE_CODING;
518 USETW(req.wValue, 0);
519 USETW(req.wIndex, sc->sc_iface_number);
520 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
521
522 err = usbd_do_request(sc->sc_udev, &req, state);
523 if (err) {
524 DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
525 usbd_errstr(err)));
526 return (err);
527 }
528
529 sc->sc_line_state = *state;
530
531 return (USBD_NORMAL_COMPLETION);
532 }
533
534 int
535 uplcom_param(void *addr, int portno, struct termios *t)
536 {
537 struct uplcom_softc *sc = addr;
538 usbd_status err;
539 usb_cdc_line_state_t ls;
540
541 DPRINTF(("uplcom_param: sc=%p\n", sc));
542
543 USETDW(ls.dwDTERate, t->c_ospeed);
544 if (ISSET(t->c_cflag, CSTOPB))
545 ls.bCharFormat = UCDC_STOP_BIT_2;
546 else
547 ls.bCharFormat = UCDC_STOP_BIT_1;
548 if (ISSET(t->c_cflag, PARENB)) {
549 if (ISSET(t->c_cflag, PARODD))
550 ls.bParityType = UCDC_PARITY_ODD;
551 else
552 ls.bParityType = UCDC_PARITY_EVEN;
553 } else
554 ls.bParityType = UCDC_PARITY_NONE;
555 switch (ISSET(t->c_cflag, CSIZE)) {
556 case CS5:
557 ls.bDataBits = 5;
558 break;
559 case CS6:
560 ls.bDataBits = 6;
561 break;
562 case CS7:
563 ls.bDataBits = 7;
564 break;
565 case CS8:
566 ls.bDataBits = 8;
567 break;
568 }
569
570 err = uplcom_set_line_coding(sc, &ls);
571 if (err) {
572 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
573 return (EIO);
574 }
575 return (0);
576 }
577
578 int
579 uplcom_open(void *addr, int portno)
580 {
581 struct uplcom_softc *sc = addr;
582 int err;
583
584 if (sc->sc_dying)
585 return (EIO);
586
587 DPRINTF(("uplcom_open: sc=%p\n", sc));
588
589 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
590 sc->sc_status = 0; /* clear status bit */
591 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
592 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
593 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
594 sc->sc_intr_buf, sc->sc_isize,
595 uplcom_intr, USBD_DEFAULT_INTERVAL);
596 if (err) {
597 DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
598 USBDEVNAME(sc->sc_dev), sc->sc_intr_number));
599 return (EIO);
600 }
601 }
602
603 return (0);
604 }
605
606 void
607 uplcom_close(void *addr, int portno)
608 {
609 struct uplcom_softc *sc = addr;
610 int err;
611
612 if (sc->sc_dying)
613 return;
614
615 DPRINTF(("uplcom_close: close\n"));
616
617 if (sc->sc_intr_pipe != NULL) {
618 err = usbd_abort_pipe(sc->sc_intr_pipe);
619 if (err)
620 printf("%s: abort interrupt pipe failed: %s\n",
621 USBDEVNAME(sc->sc_dev), usbd_errstr(err));
622 err = usbd_close_pipe(sc->sc_intr_pipe);
623 if (err)
624 printf("%s: close interrupt pipe failed: %s\n",
625 USBDEVNAME(sc->sc_dev), usbd_errstr(err));
626 free(sc->sc_intr_buf, M_USBDEV);
627 sc->sc_intr_pipe = NULL;
628 }
629 }
630
631 void
632 uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
633 {
634 struct uplcom_softc *sc = priv;
635 u_char *buf = sc->sc_intr_buf;
636 u_char pstatus;
637
638 if (sc->sc_dying)
639 return;
640
641 if (status != USBD_NORMAL_COMPLETION) {
642 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
643 return;
644
645 DPRINTF(("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev),
646 usbd_errstr(status)));
647 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
648 return;
649 }
650
651 DPRINTF(("%s: uplcom status = %02x\n", USBDEVNAME(sc->sc_dev), buf[8]));
652
653 sc->sc_lsr = sc->sc_msr = 0;
654 pstatus = buf[8];
655 if (ISSET(pstatus, RSAQ_STATUS_DSR))
656 sc->sc_msr |= UMSR_DSR;
657 if (ISSET(pstatus, RSAQ_STATUS_DCD))
658 sc->sc_msr |= UMSR_DCD;
659 ucom_status_change((struct ucom_softc *) sc->sc_subdev);
660 }
661
662 void
663 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
664 {
665 struct uplcom_softc *sc = addr;
666
667 DPRINTF(("uplcom_get_status:\n"));
668
669 if (lsr != NULL)
670 *lsr = sc->sc_lsr;
671 if (msr != NULL)
672 *msr = sc->sc_msr;
673 }
674
675 #if TODO
676 int
677 uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
678 struct proc *p)
679 {
680 struct uplcom_softc *sc = addr;
681 int error = 0;
682
683 if (sc->sc_dying)
684 return (EIO);
685
686 DPRINTF(("uplcom_ioctl: cmd=0x%08lx\n", cmd));
687
688 switch (cmd) {
689 case TIOCNOTTY:
690 case TIOCMGET:
691 case TIOCMSET:
692 case USB_GET_CM_OVER_DATA:
693 case USB_SET_CM_OVER_DATA:
694 break;
695
696 default:
697 DPRINTF(("uplcom_ioctl: unknown\n"));
698 error = ENOTTY;
699 break;
700 }
701
702 return (error);
703 }
704 #endif
705