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