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