]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/serial/uvscom.c
Rename the ushub device class back to uhub as it was in the old usb stack,
[FreeBSD/FreeBSD.git] / sys / dev / usb / serial / uvscom.c
1 /*      $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $  */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5
6 /*-
7  * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8  * All rights reserved.
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  */
32
33 /*
34  * uvscom: SUNTAC Slipper U VS-10U driver.
35  * Slipper U is a PC Card to USB converter for data communication card
36  * adapter.  It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in,
37  * P-in m@ater and various data communication card adapters.
38  */
39
40 #include "usbdevs.h"
41 #include <dev/usb/usb.h>
42 #include <dev/usb/usb_mfunc.h>
43 #include <dev/usb/usb_error.h>
44 #include <dev/usb/usb_cdc.h>
45
46 #define USB_DEBUG_VAR uvscom_debug
47
48 #include <dev/usb/usb_core.h>
49 #include <dev/usb/usb_debug.h>
50 #include <dev/usb/usb_process.h>
51 #include <dev/usb/usb_request.h>
52 #include <dev/usb/usb_lookup.h>
53 #include <dev/usb/usb_util.h>
54 #include <dev/usb/usb_busdma.h>
55
56 #include <dev/usb/serial/usb_serial.h>
57
58 #if USB_DEBUG
59 static int uvscom_debug = 0;
60
61 SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
62 SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW,
63     &uvscom_debug, 0, "Debug level");
64 #endif
65
66 #define UVSCOM_MODVER           1       /* module version */
67
68 #define UVSCOM_CONFIG_INDEX     0
69 #define UVSCOM_IFACE_INDEX      0
70
71 /* Request */
72 #define UVSCOM_SET_SPEED        0x10
73 #define UVSCOM_LINE_CTL         0x11
74 #define UVSCOM_SET_PARAM        0x12
75 #define UVSCOM_READ_STATUS      0xd0
76 #define UVSCOM_SHUTDOWN         0xe0
77
78 /* UVSCOM_SET_SPEED parameters */
79 #define UVSCOM_SPEED_150BPS     0x00
80 #define UVSCOM_SPEED_300BPS     0x01
81 #define UVSCOM_SPEED_600BPS     0x02
82 #define UVSCOM_SPEED_1200BPS    0x03
83 #define UVSCOM_SPEED_2400BPS    0x04
84 #define UVSCOM_SPEED_4800BPS    0x05
85 #define UVSCOM_SPEED_9600BPS    0x06
86 #define UVSCOM_SPEED_19200BPS   0x07
87 #define UVSCOM_SPEED_38400BPS   0x08
88 #define UVSCOM_SPEED_57600BPS   0x09
89 #define UVSCOM_SPEED_115200BPS  0x0a
90
91 /* UVSCOM_LINE_CTL parameters */
92 #define UVSCOM_BREAK            0x40
93 #define UVSCOM_RTS              0x02
94 #define UVSCOM_DTR              0x01
95 #define UVSCOM_LINE_INIT        0x08
96
97 /* UVSCOM_SET_PARAM parameters */
98 #define UVSCOM_DATA_MASK        0x03
99 #define UVSCOM_DATA_BIT_8       0x03
100 #define UVSCOM_DATA_BIT_7       0x02
101 #define UVSCOM_DATA_BIT_6       0x01
102 #define UVSCOM_DATA_BIT_5       0x00
103
104 #define UVSCOM_STOP_MASK        0x04
105 #define UVSCOM_STOP_BIT_2       0x04
106 #define UVSCOM_STOP_BIT_1       0x00
107
108 #define UVSCOM_PARITY_MASK      0x18
109 #define UVSCOM_PARITY_EVEN      0x18
110 #define UVSCOM_PARITY_ODD       0x08
111 #define UVSCOM_PARITY_NONE      0x00
112
113 /* Status bits */
114 #define UVSCOM_TXRDY            0x04
115 #define UVSCOM_RXRDY            0x01
116
117 #define UVSCOM_DCD              0x08
118 #define UVSCOM_NOCARD           0x04
119 #define UVSCOM_DSR              0x02
120 #define UVSCOM_CTS              0x01
121 #define UVSCOM_USTAT_MASK       (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
122
123 #define UVSCOM_BULK_BUF_SIZE    1024    /* bytes */
124
125 enum {
126         UVSCOM_BULK_DT_WR,
127         UVSCOM_BULK_DT_RD,
128         UVSCOM_INTR_DT_RD,
129         UVSCOM_N_TRANSFER,
130 };
131
132 struct uvscom_softc {
133         struct usb2_com_super_softc sc_super_ucom;
134         struct usb2_com_softc sc_ucom;
135
136         struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER];
137         struct usb2_device *sc_udev;
138         struct mtx sc_mtx;
139
140         uint16_t sc_line;               /* line control register */
141
142         uint8_t sc_iface_no;            /* interface number */
143         uint8_t sc_iface_index;         /* interface index */
144         uint8_t sc_lsr;                 /* local status register */
145         uint8_t sc_msr;                 /* uvscom status register */
146         uint8_t sc_unit_status;         /* unit status */
147 };
148
149 /* prototypes */
150
151 static device_probe_t uvscom_probe;
152 static device_attach_t uvscom_attach;
153 static device_detach_t uvscom_detach;
154
155 static usb2_callback_t uvscom_write_callback;
156 static usb2_callback_t uvscom_read_callback;
157 static usb2_callback_t uvscom_intr_callback;
158
159 static void     uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
160 static void     uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t);
161 static void     uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t);
162 static int      uvscom_pre_param(struct usb2_com_softc *, struct termios *);
163 static void     uvscom_cfg_param(struct usb2_com_softc *, struct termios *);
164 static int      uvscom_pre_open(struct usb2_com_softc *);
165 static void     uvscom_cfg_open(struct usb2_com_softc *);
166 static void     uvscom_cfg_close(struct usb2_com_softc *);
167 static void     uvscom_start_read(struct usb2_com_softc *);
168 static void     uvscom_stop_read(struct usb2_com_softc *);
169 static void     uvscom_start_write(struct usb2_com_softc *);
170 static void     uvscom_stop_write(struct usb2_com_softc *);
171 static void     uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
172                     uint8_t *);
173 static void     uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t);
174 static uint16_t uvscom_cfg_read_status(struct uvscom_softc *);
175
176 static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = {
177
178         [UVSCOM_BULK_DT_WR] = {
179                 .type = UE_BULK,
180                 .endpoint = UE_ADDR_ANY,
181                 .direction = UE_DIR_OUT,
182                 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
183                 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
184                 .mh.callback = &uvscom_write_callback,
185         },
186
187         [UVSCOM_BULK_DT_RD] = {
188                 .type = UE_BULK,
189                 .endpoint = UE_ADDR_ANY,
190                 .direction = UE_DIR_IN,
191                 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
192                 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
193                 .mh.callback = &uvscom_read_callback,
194         },
195
196         [UVSCOM_INTR_DT_RD] = {
197                 .type = UE_INTERRUPT,
198                 .endpoint = UE_ADDR_ANY,
199                 .direction = UE_DIR_IN,
200                 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
201                 .mh.bufsize = 0,        /* use wMaxPacketSize */
202                 .mh.callback = &uvscom_intr_callback,
203         },
204 };
205
206 static const struct usb2_com_callback uvscom_callback = {
207         .usb2_com_cfg_get_status = &uvscom_cfg_get_status,
208         .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr,
209         .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts,
210         .usb2_com_cfg_set_break = &uvscom_cfg_set_break,
211         .usb2_com_cfg_param = &uvscom_cfg_param,
212         .usb2_com_cfg_open = &uvscom_cfg_open,
213         .usb2_com_cfg_close = &uvscom_cfg_close,
214         .usb2_com_pre_open = &uvscom_pre_open,
215         .usb2_com_pre_param = &uvscom_pre_param,
216         .usb2_com_start_read = &uvscom_start_read,
217         .usb2_com_stop_read = &uvscom_stop_read,
218         .usb2_com_start_write = &uvscom_start_write,
219         .usb2_com_stop_write = &uvscom_stop_write,
220 };
221
222 static const struct usb2_device_id uvscom_devs[] = {
223         /* SUNTAC U-Cable type A4 */
224         {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)},
225         /* SUNTAC U-Cable type D2 */
226         {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)},
227         /* SUNTAC Ir-Trinity */
228         {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)},
229         /* SUNTAC U-Cable type P1 */
230         {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)},
231         /* SUNTAC Slipper U */
232         {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)},
233 };
234
235 static device_method_t uvscom_methods[] = {
236         DEVMETHOD(device_probe, uvscom_probe),
237         DEVMETHOD(device_attach, uvscom_attach),
238         DEVMETHOD(device_detach, uvscom_detach),
239         {0, 0}
240 };
241
242 static devclass_t uvscom_devclass;
243
244 static driver_t uvscom_driver = {
245         .name = "uvscom",
246         .methods = uvscom_methods,
247         .size = sizeof(struct uvscom_softc),
248 };
249
250 DRIVER_MODULE(uvscom, uhub, uvscom_driver, uvscom_devclass, NULL, 0);
251 MODULE_DEPEND(uvscom, ucom, 1, 1, 1);
252 MODULE_DEPEND(uvscom, usb, 1, 1, 1);
253 MODULE_VERSION(uvscom, UVSCOM_MODVER);
254
255 static int
256 uvscom_probe(device_t dev)
257 {
258         struct usb2_attach_arg *uaa = device_get_ivars(dev);
259
260         if (uaa->usb2_mode != USB_MODE_HOST) {
261                 return (ENXIO);
262         }
263         if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) {
264                 return (ENXIO);
265         }
266         if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) {
267                 return (ENXIO);
268         }
269         return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa));
270 }
271
272 static int
273 uvscom_attach(device_t dev)
274 {
275         struct usb2_attach_arg *uaa = device_get_ivars(dev);
276         struct uvscom_softc *sc = device_get_softc(dev);
277         int error;
278
279         device_set_usb2_desc(dev);
280         mtx_init(&sc->sc_mtx, "uvscom", NULL, MTX_DEF);
281
282         sc->sc_udev = uaa->device;
283
284         DPRINTF("sc=%p\n", sc);
285
286         sc->sc_iface_no = uaa->info.bIfaceNum;
287         sc->sc_iface_index = UVSCOM_IFACE_INDEX;
288
289         error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index,
290             sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &sc->sc_mtx);
291
292         if (error) {
293                 DPRINTF("could not allocate all USB transfers!\n");
294                 goto detach;
295         }
296         sc->sc_line = UVSCOM_LINE_INIT;
297
298         /* clear stall at first run */
299         mtx_lock(&sc->sc_mtx);
300         usb2_transfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
301         usb2_transfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
302         mtx_unlock(&sc->sc_mtx);
303
304         error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
305             &uvscom_callback, &sc->sc_mtx);
306         if (error) {
307                 goto detach;
308         }
309         /* start interrupt pipe */
310         mtx_lock(&sc->sc_mtx);
311         usb2_transfer_start(sc->sc_xfer[UVSCOM_INTR_DT_RD]);
312         mtx_unlock(&sc->sc_mtx);
313
314         return (0);
315
316 detach:
317         uvscom_detach(dev);
318         return (ENXIO);
319 }
320
321 static int
322 uvscom_detach(device_t dev)
323 {
324         struct uvscom_softc *sc = device_get_softc(dev);
325
326         DPRINTF("sc=%p\n", sc);
327
328         /* stop interrupt pipe */
329
330         if (sc->sc_xfer[UVSCOM_INTR_DT_RD])
331                 usb2_transfer_stop(sc->sc_xfer[UVSCOM_INTR_DT_RD]);
332
333         usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
334         usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER);
335         mtx_destroy(&sc->sc_mtx);
336
337         return (0);
338 }
339
340 static void
341 uvscom_write_callback(struct usb2_xfer *xfer)
342 {
343         struct uvscom_softc *sc = xfer->priv_sc;
344         uint32_t actlen;
345
346         switch (USB_GET_STATE(xfer)) {
347         case USB_ST_SETUP:
348         case USB_ST_TRANSFERRED:
349 tr_setup:
350                 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
351                     UVSCOM_BULK_BUF_SIZE, &actlen)) {
352
353                         xfer->frlengths[0] = actlen;
354                         usb2_start_hardware(xfer);
355                 }
356                 return;
357
358         default:                        /* Error */
359                 if (xfer->error != USB_ERR_CANCELLED) {
360                         /* try to clear stall first */
361                         xfer->flags.stall_pipe = 1;
362                         goto tr_setup;
363                 }
364                 return;
365         }
366 }
367
368 static void
369 uvscom_read_callback(struct usb2_xfer *xfer)
370 {
371         struct uvscom_softc *sc = xfer->priv_sc;
372
373         switch (USB_GET_STATE(xfer)) {
374         case USB_ST_TRANSFERRED:
375                 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
376
377         case USB_ST_SETUP:
378 tr_setup:
379                 xfer->frlengths[0] = xfer->max_data_length;
380                 usb2_start_hardware(xfer);
381                 return;
382
383         default:                        /* Error */
384                 if (xfer->error != USB_ERR_CANCELLED) {
385                         /* try to clear stall first */
386                         xfer->flags.stall_pipe = 1;
387                         goto tr_setup;
388                 }
389                 return;
390         }
391 }
392
393 static void
394 uvscom_intr_callback(struct usb2_xfer *xfer)
395 {
396         struct uvscom_softc *sc = xfer->priv_sc;
397         uint8_t buf[2];
398
399         switch (USB_GET_STATE(xfer)) {
400         case USB_ST_TRANSFERRED:
401                 if (xfer->actlen >= 2) {
402
403                         usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
404
405                         sc->sc_lsr = 0;
406                         sc->sc_msr = 0;
407                         sc->sc_unit_status = buf[1];
408
409                         if (buf[0] & UVSCOM_TXRDY) {
410                                 sc->sc_lsr |= ULSR_TXRDY;
411                         }
412                         if (buf[0] & UVSCOM_RXRDY) {
413                                 sc->sc_lsr |= ULSR_RXRDY;
414                         }
415                         if (buf[1] & UVSCOM_CTS) {
416                                 sc->sc_msr |= SER_CTS;
417                         }
418                         if (buf[1] & UVSCOM_DSR) {
419                                 sc->sc_msr |= SER_DSR;
420                         }
421                         if (buf[1] & UVSCOM_DCD) {
422                                 sc->sc_msr |= SER_DCD;
423                         }
424                         /*
425                          * the UCOM layer will ignore this call if the TTY
426                          * device is closed!
427                          */
428                         usb2_com_status_change(&sc->sc_ucom);
429                 }
430         case USB_ST_SETUP:
431 tr_setup:
432                 xfer->frlengths[0] = xfer->max_data_length;
433                 usb2_start_hardware(xfer);
434                 return;
435
436         default:                        /* Error */
437                 if (xfer->error != USB_ERR_CANCELLED) {
438                         /* try to clear stall first */
439                         xfer->flags.stall_pipe = 1;
440                         goto tr_setup;
441                 }
442                 return;
443         }
444 }
445
446 static void
447 uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
448 {
449         struct uvscom_softc *sc = ucom->sc_parent;
450
451         DPRINTF("onoff = %d\n", onoff);
452
453         if (onoff)
454                 sc->sc_line |= UVSCOM_DTR;
455         else
456                 sc->sc_line &= ~UVSCOM_DTR;
457
458         uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
459 }
460
461 static void
462 uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
463 {
464         struct uvscom_softc *sc = ucom->sc_parent;
465
466         DPRINTF("onoff = %d\n", onoff);
467
468         if (onoff)
469                 sc->sc_line |= UVSCOM_RTS;
470         else
471                 sc->sc_line &= ~UVSCOM_RTS;
472
473         uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
474 }
475
476 static void
477 uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
478 {
479         struct uvscom_softc *sc = ucom->sc_parent;
480
481         DPRINTF("onoff = %d\n", onoff);
482
483         if (onoff)
484                 sc->sc_line |= UVSCOM_BREAK;
485         else
486                 sc->sc_line &= ~UVSCOM_BREAK;
487
488         uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
489 }
490
491 static int
492 uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
493 {
494         switch (t->c_ospeed) {
495                 case B150:
496                 case B300:
497                 case B600:
498                 case B1200:
499                 case B2400:
500                 case B4800:
501                 case B9600:
502                 case B19200:
503                 case B38400:
504                 case B57600:
505                 case B115200:
506                 default:
507                 return (EINVAL);
508         }
509         return (0);
510 }
511
512 static void
513 uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
514 {
515         struct uvscom_softc *sc = ucom->sc_parent;
516         uint16_t value;
517
518         DPRINTF("\n");
519
520         switch (t->c_ospeed) {
521         case B150:
522                 value = UVSCOM_SPEED_150BPS;
523                 break;
524         case B300:
525                 value = UVSCOM_SPEED_300BPS;
526                 break;
527         case B600:
528                 value = UVSCOM_SPEED_600BPS;
529                 break;
530         case B1200:
531                 value = UVSCOM_SPEED_1200BPS;
532                 break;
533         case B2400:
534                 value = UVSCOM_SPEED_2400BPS;
535                 break;
536         case B4800:
537                 value = UVSCOM_SPEED_4800BPS;
538                 break;
539         case B9600:
540                 value = UVSCOM_SPEED_9600BPS;
541                 break;
542         case B19200:
543                 value = UVSCOM_SPEED_19200BPS;
544                 break;
545         case B38400:
546                 value = UVSCOM_SPEED_38400BPS;
547                 break;
548         case B57600:
549                 value = UVSCOM_SPEED_57600BPS;
550                 break;
551         case B115200:
552                 value = UVSCOM_SPEED_115200BPS;
553                 break;
554         default:
555                 return;
556         }
557
558         uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value);
559
560         value = 0;
561
562         if (t->c_cflag & CSTOPB) {
563                 value |= UVSCOM_STOP_BIT_2;
564         }
565         if (t->c_cflag & PARENB) {
566                 if (t->c_cflag & PARODD) {
567                         value |= UVSCOM_PARITY_ODD;
568                 } else {
569                         value |= UVSCOM_PARITY_EVEN;
570                 }
571         } else {
572                 value |= UVSCOM_PARITY_NONE;
573         }
574
575         switch (t->c_cflag & CSIZE) {
576         case CS5:
577                 value |= UVSCOM_DATA_BIT_5;
578                 break;
579         case CS6:
580                 value |= UVSCOM_DATA_BIT_6;
581                 break;
582         case CS7:
583                 value |= UVSCOM_DATA_BIT_7;
584                 break;
585         default:
586         case CS8:
587                 value |= UVSCOM_DATA_BIT_8;
588                 break;
589         }
590
591         uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value);
592 }
593
594 static int
595 uvscom_pre_open(struct usb2_com_softc *ucom)
596 {
597         struct uvscom_softc *sc = ucom->sc_parent;
598
599         DPRINTF("sc = %p\n", sc);
600
601         /* check if PC card was inserted */
602
603         if (sc->sc_unit_status & UVSCOM_NOCARD) {
604                 DPRINTF("no PC card!\n");
605                 return (ENXIO);
606         }
607         return (0);
608 }
609
610 static void
611 uvscom_cfg_open(struct usb2_com_softc *ucom)
612 {
613         struct uvscom_softc *sc = ucom->sc_parent;
614
615         DPRINTF("sc = %p\n", sc);
616
617         uvscom_cfg_read_status(sc);
618 }
619
620 static void
621 uvscom_cfg_close(struct usb2_com_softc *ucom)
622 {
623         struct uvscom_softc *sc = ucom->sc_parent;
624
625         DPRINTF("sc=%p\n", sc);
626
627         uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0);
628 }
629
630 static void
631 uvscom_start_read(struct usb2_com_softc *ucom)
632 {
633         struct uvscom_softc *sc = ucom->sc_parent;
634
635         usb2_transfer_start(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
636 }
637
638 static void
639 uvscom_stop_read(struct usb2_com_softc *ucom)
640 {
641         struct uvscom_softc *sc = ucom->sc_parent;
642
643         usb2_transfer_stop(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
644 }
645
646 static void
647 uvscom_start_write(struct usb2_com_softc *ucom)
648 {
649         struct uvscom_softc *sc = ucom->sc_parent;
650
651         usb2_transfer_start(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
652 }
653
654 static void
655 uvscom_stop_write(struct usb2_com_softc *ucom)
656 {
657         struct uvscom_softc *sc = ucom->sc_parent;
658
659         usb2_transfer_stop(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
660 }
661
662 static void
663 uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
664 {
665         struct uvscom_softc *sc = ucom->sc_parent;
666
667         *lsr = sc->sc_lsr;
668         *msr = sc->sc_msr;
669 }
670
671 static void
672 uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value)
673 {
674         struct usb2_device_request req;
675         usb2_error_t err;
676
677         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
678         req.bRequest = index;
679         USETW(req.wValue, value);
680         USETW(req.wIndex, 0);
681         USETW(req.wLength, 0);
682
683         err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
684             &req, NULL, 0, 1000);
685         if (err) {
686                 DPRINTFN(0, "device request failed, err=%s "
687                     "(ignored)\n", usb2_errstr(err));
688         }
689 }
690
691 static uint16_t
692 uvscom_cfg_read_status(struct uvscom_softc *sc)
693 {
694         struct usb2_device_request req;
695         usb2_error_t err;
696         uint8_t data[2];
697
698         req.bmRequestType = UT_READ_VENDOR_DEVICE;
699         req.bRequest = UVSCOM_READ_STATUS;
700         USETW(req.wValue, 0);
701         USETW(req.wIndex, 0);
702         USETW(req.wLength, 2);
703
704         err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
705             &req, data, 0, 1000);
706         if (err) {
707                 DPRINTFN(0, "device request failed, err=%s "
708                     "(ignored)\n", usb2_errstr(err));
709         }
710         return (data[0] | (data[1] << 8));
711 }