Line data Source code
1 : /* $OpenBSD: umct.c,v 1.47 2017/12/30 20:47:00 guenther Exp $ */
2 : /* $NetBSD: umct.c,v 1.10 2003/02/23 04:20:07 simonb Exp $ */
3 : /*
4 : * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 : * All rights reserved.
6 : *
7 : * This code is derived from software contributed to The NetBSD Foundation
8 : * by Ichiro FUKUHARA (ichiro@ichiro.org).
9 : *
10 : * Redistribution and use in source and binary forms, with or without
11 : * modification, are permitted provided that the following conditions
12 : * are met:
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 : * POSSIBILITY OF SUCH DAMAGE.
30 : */
31 :
32 : /*
33 : * MCT USB-RS232 Interface Controller
34 : * http://www.mct.com.tw/prod/rs232.html
35 : * http://www.dlink.com/products/usb/dsbs25
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/ioctl.h>
43 : #include <sys/conf.h>
44 : #include <sys/tty.h>
45 : #include <sys/selinfo.h>
46 : #include <sys/device.h>
47 : #include <sys/poll.h>
48 :
49 : #include <dev/usb/usb.h>
50 : #include <dev/usb/usbcdc.h>
51 :
52 : #include <dev/usb/usbdi.h>
53 : #include <dev/usb/usbdi_util.h>
54 : #include <dev/usb/usbdevs.h>
55 :
56 : #include <dev/usb/ucomvar.h>
57 :
58 : #include <dev/usb/umct.h>
59 :
60 : #ifdef UMCT_DEBUG
61 : #define DPRINTFN(n, x) do { if (umctdebug > (n)) printf x; } while (0)
62 : int umctdebug = 0;
63 : #else
64 : #define DPRINTFN(n, x)
65 : #endif
66 : #define DPRINTF(x) DPRINTFN(0, x)
67 :
68 : #define UMCT_IFACE_INDEX 0
69 :
70 : struct umct_softc {
71 : struct device sc_dev; /* base device */
72 : struct usbd_device *sc_udev; /* USB device */
73 : struct usbd_interface *sc_iface; /* interface */
74 : int sc_iface_number; /* interface number */
75 : u_int16_t sc_product;
76 :
77 : int sc_intr_number; /* interrupt number */
78 : struct usbd_pipe *sc_intr_pipe; /* interrupt pipe */
79 : u_char *sc_intr_buf; /* interrupt buffer */
80 : int sc_isize;
81 :
82 : struct usb_cdc_line_state sc_line_state; /* current line state */
83 : u_char sc_dtr; /* current DTR state */
84 : u_char sc_rts; /* current RTS state */
85 : u_char sc_break; /* set break */
86 :
87 : u_char sc_status;
88 :
89 : struct device *sc_subdev; /* ucom device */
90 :
91 : u_char sc_lsr; /* Local status register */
92 : u_char sc_msr; /* umct status register */
93 :
94 : u_int last_lcr; /* keep lcr register */
95 : };
96 :
97 : /*
98 : * These are the maximum number of bytes transferred per frame.
99 : * The output buffer size cannot be increased due to the size encoding.
100 : */
101 : #define UMCTIBUFSIZE 256
102 : #define UMCTOBUFSIZE 256
103 :
104 : void umct_init(struct umct_softc *);
105 : void umct_set_baudrate(struct umct_softc *, u_int, int);
106 : void umct_set_lcr(struct umct_softc *, u_int);
107 : void umct_intr(struct usbd_xfer *, void *, usbd_status);
108 :
109 : void umct_set(void *, int, int, int);
110 : void umct_dtr(struct umct_softc *, int);
111 : void umct_rts(struct umct_softc *, int);
112 : void umct_break(struct umct_softc *, int);
113 : void umct_set_line_state(struct umct_softc *);
114 : void umct_get_status(void *, int portno, u_char *lsr, u_char *msr);
115 : int umct_param(void *, int, struct termios *);
116 : int umct_open(void *, int);
117 : void umct_close(void *, int);
118 :
119 : struct ucom_methods umct_methods = {
120 : umct_get_status,
121 : umct_set,
122 : umct_param,
123 : NULL,
124 : umct_open,
125 : umct_close,
126 : NULL,
127 : NULL,
128 : };
129 :
130 : static const struct usb_devno umct_devs[] = {
131 : /* MCT USB-232 Interface Products */
132 : { USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232 },
133 : /* Sitecom USB-232 Products */
134 : { USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232 },
135 : /* D-Link DU-H3SP USB BAY Hub Products */
136 : { USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232 },
137 : /* BELKIN F5U109 */
138 : { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109 },
139 : /* BELKIN F5U409 */
140 : { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409 },
141 : };
142 :
143 : int umct_match(struct device *, void *, void *);
144 : void umct_attach(struct device *, struct device *, void *);
145 : int umct_detach(struct device *, int);
146 :
147 : struct cfdriver umct_cd = {
148 : NULL, "umct", DV_DULL
149 : };
150 :
151 : const struct cfattach umct_ca = {
152 : sizeof(struct umct_softc), umct_match, umct_attach, umct_detach
153 : };
154 :
155 : int
156 0 : umct_match(struct device *parent, void *match, void *aux)
157 : {
158 0 : struct usb_attach_arg *uaa = aux;
159 :
160 0 : if (uaa->iface == NULL)
161 0 : return (UMATCH_NONE);
162 :
163 0 : return (usb_lookup(umct_devs, uaa->vendor, uaa->product) != NULL ?
164 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
165 0 : }
166 :
167 : void
168 0 : umct_attach(struct device *parent, struct device *self, void *aux)
169 : {
170 0 : struct umct_softc *sc = (struct umct_softc *)self;
171 0 : struct usb_attach_arg *uaa = aux;
172 0 : struct usbd_device *dev = uaa->device;
173 : usb_config_descriptor_t *cdesc;
174 : usb_interface_descriptor_t *id;
175 : usb_endpoint_descriptor_t *ed;
176 :
177 0 : char *devname = sc->sc_dev.dv_xname;
178 : usbd_status err;
179 : int i;
180 0 : struct ucom_attach_args uca;
181 :
182 0 : sc->sc_udev = dev;
183 0 : sc->sc_product = uaa->product;
184 :
185 : DPRINTF(("\n\numct attach: sc=%p\n", sc));
186 :
187 : /* initialize endpoints */
188 0 : uca.bulkin = uca.bulkout = -1;
189 0 : sc->sc_intr_number = -1;
190 0 : sc->sc_intr_pipe = NULL;
191 :
192 : /* get the config descriptor */
193 0 : cdesc = usbd_get_config_descriptor(sc->sc_udev);
194 :
195 0 : if (cdesc == NULL) {
196 0 : printf("%s: failed to get configuration descriptor\n",
197 : sc->sc_dev.dv_xname);
198 0 : usbd_deactivate(sc->sc_udev);
199 0 : return;
200 : }
201 :
202 : /* get the interface */
203 0 : err = usbd_device2interface_handle(dev, UMCT_IFACE_INDEX,
204 0 : &sc->sc_iface);
205 0 : if (err) {
206 0 : printf("\n%s: failed to get interface, err=%s\n",
207 0 : devname, usbd_errstr(err));
208 0 : usbd_deactivate(sc->sc_udev);
209 0 : return;
210 : }
211 :
212 : /* Find the bulk{in,out} and interrupt endpoints */
213 :
214 0 : id = usbd_get_interface_descriptor(sc->sc_iface);
215 0 : sc->sc_iface_number = id->bInterfaceNumber;
216 :
217 0 : for (i = 0; i < id->bNumEndpoints; i++) {
218 0 : ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
219 0 : if (ed == NULL) {
220 0 : printf("%s: no endpoint descriptor for %d\n",
221 : sc->sc_dev.dv_xname, i);
222 0 : usbd_deactivate(sc->sc_udev);
223 0 : return;
224 : }
225 :
226 : /*
227 : * The Bulkin endpoint is marked as an interrupt. Since
228 : * we can't rely on the endpoint descriptor order, we'll
229 : * check the wMaxPacketSize field to differentiate.
230 : */
231 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
232 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT &&
233 0 : UGETW(ed->wMaxPacketSize) != 0x2) {
234 0 : uca.bulkin = ed->bEndpointAddress;
235 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
236 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
237 0 : uca.bulkout = ed->bEndpointAddress;
238 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
239 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
240 0 : sc->sc_intr_number = ed->bEndpointAddress;
241 0 : sc->sc_isize = UGETW(ed->wMaxPacketSize);
242 0 : }
243 : }
244 :
245 0 : if (uca.bulkin == -1) {
246 0 : printf("%s: Could not find data bulk in\n",
247 : sc->sc_dev.dv_xname);
248 0 : usbd_deactivate(sc->sc_udev);
249 0 : return;
250 : }
251 :
252 0 : if (uca.bulkout == -1) {
253 0 : printf("%s: Could not find data bulk out\n",
254 : sc->sc_dev.dv_xname);
255 0 : usbd_deactivate(sc->sc_udev);
256 0 : return;
257 : }
258 :
259 0 : if (sc->sc_intr_number== -1) {
260 0 : printf("%s: Could not find interrupt in\n",
261 : sc->sc_dev.dv_xname);
262 0 : usbd_deactivate(sc->sc_udev);
263 0 : return;
264 : }
265 :
266 0 : sc->sc_dtr = sc->sc_rts = 0;
267 0 : uca.portno = UCOM_UNK_PORTNO;
268 : /* bulkin, bulkout set above */
269 0 : uca.ibufsize = UMCTIBUFSIZE;
270 0 : if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232)
271 0 : uca.obufsize = 16; /* device is broken */
272 : else
273 0 : uca.obufsize = UMCTOBUFSIZE;
274 0 : uca.ibufsizepad = UMCTIBUFSIZE;
275 0 : uca.opkthdrlen = 0;
276 0 : uca.device = dev;
277 0 : uca.iface = sc->sc_iface;
278 0 : uca.methods = &umct_methods;
279 0 : uca.arg = sc;
280 0 : uca.info = NULL;
281 :
282 0 : umct_init(sc);
283 :
284 : DPRINTF(("umct: in=0x%x out=0x%x intr=0x%x\n",
285 : uca.bulkin, uca.bulkout, sc->sc_intr_number ));
286 0 : sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
287 0 : }
288 :
289 : int
290 0 : umct_detach(struct device *self, int flags)
291 : {
292 0 : struct umct_softc *sc = (struct umct_softc *)self;
293 : int rv = 0;
294 :
295 : DPRINTF(("umct_detach: sc=%p flags=%d\n", sc, flags));
296 :
297 0 : if (sc->sc_intr_pipe != NULL) {
298 0 : usbd_abort_pipe(sc->sc_intr_pipe);
299 0 : usbd_close_pipe(sc->sc_intr_pipe);
300 0 : free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
301 0 : sc->sc_intr_pipe = NULL;
302 0 : }
303 :
304 0 : if (sc->sc_subdev != NULL) {
305 0 : rv = config_detach(sc->sc_subdev, flags);
306 0 : sc->sc_subdev = NULL;
307 0 : }
308 :
309 0 : return (rv);
310 : }
311 :
312 : void
313 0 : umct_set_line_state(struct umct_softc *sc)
314 : {
315 0 : usb_device_request_t req;
316 0 : uByte ls;
317 :
318 0 : ls = (sc->sc_dtr ? MCR_DTR : 0) |
319 0 : (sc->sc_rts ? MCR_RTS : 0);
320 :
321 : DPRINTF(("umct_set_line_state: DTR=%d,RTS=%d,ls=%02x\n",
322 : sc->sc_dtr, sc->sc_rts, ls));
323 :
324 0 : req.bmRequestType = UMCT_SET_REQUEST;
325 0 : req.bRequest = REQ_SET_MCR;
326 0 : USETW(req.wValue, 0);
327 0 : USETW(req.wIndex, sc->sc_iface_number);
328 0 : USETW(req.wLength, LENGTH_SET_MCR);
329 :
330 0 : (void)usbd_do_request(sc->sc_udev, &req, &ls);
331 0 : }
332 :
333 : void
334 0 : umct_set(void *addr, int portno, int reg, int onoff)
335 : {
336 0 : struct umct_softc *sc = addr;
337 :
338 0 : switch (reg) {
339 : case UCOM_SET_DTR:
340 0 : umct_dtr(sc, onoff);
341 0 : break;
342 : case UCOM_SET_RTS:
343 0 : umct_rts(sc, onoff);
344 0 : break;
345 : case UCOM_SET_BREAK:
346 0 : umct_break(sc, onoff);
347 0 : break;
348 : default:
349 : break;
350 : }
351 0 : }
352 :
353 : void
354 0 : umct_dtr(struct umct_softc *sc, int onoff)
355 : {
356 :
357 : DPRINTF(("umct_dtr: onoff=%d\n", onoff));
358 :
359 0 : if (sc->sc_dtr == onoff)
360 : return;
361 0 : sc->sc_dtr = onoff;
362 :
363 0 : umct_set_line_state(sc);
364 0 : }
365 :
366 : void
367 0 : umct_rts(struct umct_softc *sc, int onoff)
368 : {
369 : DPRINTF(("umct_rts: onoff=%d\n", onoff));
370 :
371 0 : if (sc->sc_rts == onoff)
372 : return;
373 0 : sc->sc_rts = onoff;
374 :
375 0 : umct_set_line_state(sc);
376 0 : }
377 :
378 : void
379 0 : umct_break(struct umct_softc *sc, int onoff)
380 : {
381 : DPRINTF(("umct_break: onoff=%d\n", onoff));
382 :
383 0 : umct_set_lcr(sc, onoff ? sc->last_lcr | LCR_SET_BREAK :
384 : sc->last_lcr);
385 0 : }
386 :
387 : void
388 0 : umct_set_lcr(struct umct_softc *sc, u_int data)
389 : {
390 0 : usb_device_request_t req;
391 0 : uByte adata;
392 :
393 0 : adata = data;
394 0 : req.bmRequestType = UMCT_SET_REQUEST;
395 0 : req.bRequest = REQ_SET_LCR;
396 0 : USETW(req.wValue, 0);
397 0 : USETW(req.wIndex, sc->sc_iface_number);
398 0 : USETW(req.wLength, LENGTH_SET_LCR);
399 :
400 : /* XXX should check */
401 0 : (void)usbd_do_request(sc->sc_udev, &req, &adata);
402 0 : }
403 :
404 : void
405 0 : umct_set_baudrate(struct umct_softc *sc, u_int rate, int cts)
406 : {
407 0 : usb_device_request_t req;
408 0 : uDWord arate;
409 : u_int val;
410 :
411 0 : if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232 ||
412 0 : sc->sc_product == USB_PRODUCT_BELKIN_F5U109) {
413 0 : switch (rate) {
414 0 : case 300: val = 0x01; break;
415 0 : case 600: val = 0x02; break;
416 0 : case 1200: val = 0x03; break;
417 0 : case 2400: val = 0x04; break;
418 0 : case 4800: val = 0x06; break;
419 0 : case 9600: val = 0x08; break;
420 0 : case 19200: val = 0x09; break;
421 0 : case 38400: val = 0x0a; break;
422 0 : case 57600: val = 0x0b; break;
423 0 : case 115200: val = 0x0c; break;
424 0 : default: val = -1; break;
425 : }
426 : } else {
427 0 : val = UMCT_BAUD_RATE(rate);
428 : }
429 0 : USETDW(arate, val);
430 :
431 0 : req.bmRequestType = UMCT_SET_REQUEST;
432 0 : req.bRequest = REQ_SET_BAUD_RATE;
433 0 : USETW(req.wValue, 0);
434 0 : USETW(req.wIndex, sc->sc_iface_number);
435 0 : USETW(req.wLength, LENGTH_BAUD_RATE);
436 :
437 : /* XXX should check */
438 0 : (void)usbd_do_request(sc->sc_udev, &req, arate);
439 :
440 : /* unknown request, required after setting baud rate */
441 0 : USETDW(arate, 0);
442 0 : req.bmRequestType = UMCT_SET_REQUEST;
443 0 : req.bRequest = REQ_UNKNOWN1;
444 0 : USETW(req.wValue, 0);
445 0 : USETW(req.wIndex, sc->sc_iface_number);
446 0 : USETW(req.wLength, LENGTH_UNKNOWN1);
447 0 : (void)usbd_do_request(sc->sc_udev, &req, arate);
448 :
449 : /* update CTS, also required after setting baud rate */
450 0 : USETDW(arate, cts);
451 0 : req.bmRequestType = UMCT_SET_REQUEST;
452 0 : req.bRequest = REQ_SET_CTS;
453 0 : USETW(req.wValue, 0);
454 0 : USETW(req.wIndex, sc->sc_iface_number);
455 0 : USETW(req.wLength, LENGTH_SET_CTS);
456 0 : (void)usbd_do_request(sc->sc_udev, &req, arate);
457 0 : }
458 :
459 : void
460 0 : umct_init(struct umct_softc *sc)
461 : {
462 0 : umct_set_baudrate(sc, 9600, 0);
463 0 : umct_set_lcr(sc, LCR_DATA_BITS_8 | LCR_PARITY_NONE | LCR_STOP_BITS_1);
464 0 : }
465 :
466 : int
467 0 : umct_param(void *addr, int portno, struct termios *t)
468 : {
469 0 : struct umct_softc *sc = addr;
470 : u_int data = 0;
471 :
472 : DPRINTF(("umct_param: sc=%p\n", sc));
473 :
474 : DPRINTF(("umct_param: BAUDRATE=%d\n", t->c_ospeed));
475 :
476 0 : if (ISSET(t->c_cflag, CSTOPB))
477 0 : data |= LCR_STOP_BITS_2;
478 : else
479 : data |= LCR_STOP_BITS_1;
480 0 : if (ISSET(t->c_cflag, PARENB)) {
481 0 : if (ISSET(t->c_cflag, PARODD))
482 0 : data |= LCR_PARITY_ODD;
483 : else
484 0 : data |= LCR_PARITY_EVEN;
485 : } else
486 : data |= LCR_PARITY_NONE;
487 0 : switch (ISSET(t->c_cflag, CSIZE)) {
488 : case CS5:
489 : data |= LCR_DATA_BITS_5;
490 0 : break;
491 : case CS6:
492 0 : data |= LCR_DATA_BITS_6;
493 0 : break;
494 : case CS7:
495 0 : data |= LCR_DATA_BITS_7;
496 0 : break;
497 : case CS8:
498 0 : data |= LCR_DATA_BITS_8;
499 0 : break;
500 : }
501 :
502 0 : umct_set_baudrate(sc, t->c_ospeed, ISSET(t->c_cflag, CRTSCTS));
503 :
504 0 : sc->last_lcr = data;
505 0 : umct_set_lcr(sc, data);
506 :
507 0 : return (0);
508 : }
509 :
510 : int
511 0 : umct_open(void *addr, int portno)
512 : {
513 0 : struct umct_softc *sc = addr;
514 : int err, lcr_data;
515 :
516 0 : if (usbd_is_dying(sc->sc_udev))
517 0 : return (EIO);
518 :
519 : DPRINTF(("umct_open: sc=%p\n", sc));
520 :
521 : /* initialize LCR */
522 : lcr_data = LCR_DATA_BITS_8 | LCR_PARITY_NONE |
523 : LCR_STOP_BITS_1;
524 0 : umct_set_lcr(sc, lcr_data);
525 :
526 0 : if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
527 0 : sc->sc_status = 0; /* clear status bit */
528 0 : sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
529 0 : err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
530 : USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
531 0 : sc->sc_intr_buf, sc->sc_isize,
532 : umct_intr, USBD_DEFAULT_INTERVAL);
533 0 : if (err) {
534 : DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
535 : sc->sc_dev.dv_xname, sc->sc_intr_number));
536 0 : return (EIO);
537 : }
538 : }
539 :
540 0 : return (0);
541 0 : }
542 :
543 : void
544 0 : umct_close(void *addr, int portno)
545 : {
546 0 : struct umct_softc *sc = addr;
547 : int err;
548 :
549 0 : if (usbd_is_dying(sc->sc_udev))
550 0 : return;
551 :
552 : DPRINTF(("umct_close: close\n"));
553 :
554 0 : if (sc->sc_intr_pipe != NULL) {
555 0 : usbd_abort_pipe(sc->sc_intr_pipe);
556 0 : err = usbd_close_pipe(sc->sc_intr_pipe);
557 0 : if (err)
558 0 : printf("%s: close interrupt pipe failed: %s\n",
559 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
560 0 : free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
561 0 : sc->sc_intr_pipe = NULL;
562 0 : }
563 0 : }
564 :
565 : void
566 0 : umct_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
567 : {
568 0 : struct umct_softc *sc = priv;
569 0 : u_char *buf = sc->sc_intr_buf;
570 : u_char mstatus;
571 :
572 0 : if (usbd_is_dying(sc->sc_udev))
573 0 : return;
574 :
575 0 : if (status != USBD_NORMAL_COMPLETION) {
576 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
577 0 : return;
578 :
579 : DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
580 : usbd_errstr(status)));
581 0 : usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
582 0 : return;
583 : }
584 :
585 : DPRINTF(("%s: umct status = MSR:%02x, LSR:%02x\n",
586 : sc->sc_dev.dv_xname, buf[0],buf[1]));
587 :
588 0 : sc->sc_lsr = sc->sc_msr = 0;
589 0 : mstatus = buf[0];
590 0 : if (ISSET(mstatus, MSR_DSR))
591 0 : sc->sc_msr |= UMSR_DSR;
592 0 : if (ISSET(mstatus, MSR_DCD))
593 0 : sc->sc_msr |= UMSR_DCD;
594 0 : ucom_status_change((struct ucom_softc *)sc->sc_subdev);
595 0 : }
596 :
597 : void
598 0 : umct_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
599 : {
600 0 : struct umct_softc *sc = addr;
601 :
602 : DPRINTF(("umct_get_status:\n"));
603 :
604 0 : if (lsr != NULL)
605 0 : *lsr = sc->sc_lsr;
606 0 : if (msr != NULL)
607 0 : *msr = sc->sc_msr;
608 0 : }
|