Deleted Added
full compact
uvscom.c (187173) uvscom.c (187176)
1/* $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $ */
2
3#include <sys/cdefs.h>
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: head/sys/dev/usb2/serial/uvscom2.c 187173 2009-01-13 19:03:12Z thompsa $");
4__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uvscom2.c 187176 2009-01-13 19:03:47Z thompsa $");
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 <dev/usb2/include/usb2_devid.h>
41#include <dev/usb2/include/usb2_standard.h>
42#include <dev/usb2/include/usb2_mfunc.h>
43#include <dev/usb2/include/usb2_error.h>
44#include <dev/usb2/include/usb2_cdc.h>
45
46#define USB_DEBUG_VAR uvscom_debug
47
48#include <dev/usb2/core/usb2_core.h>
49#include <dev/usb2/core/usb2_debug.h>
50#include <dev/usb2/core/usb2_process.h>
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 <dev/usb2/include/usb2_devid.h>
41#include <dev/usb2/include/usb2_standard.h>
42#include <dev/usb2/include/usb2_mfunc.h>
43#include <dev/usb2/include/usb2_error.h>
44#include <dev/usb2/include/usb2_cdc.h>
45
46#define USB_DEBUG_VAR uvscom_debug
47
48#include <dev/usb2/core/usb2_core.h>
49#include <dev/usb2/core/usb2_debug.h>
50#include <dev/usb2/core/usb2_process.h>
51#include <dev/usb2/core/usb2_config_td.h>
52#include <dev/usb2/core/usb2_request.h>
53#include <dev/usb2/core/usb2_lookup.h>
54#include <dev/usb2/core/usb2_util.h>
55#include <dev/usb2/core/usb2_busdma.h>
56
57#include <dev/usb2/serial/usb2_serial.h>
58
59#if USB_DEBUG
60static int uvscom_debug = 0;
61
62SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
63SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW,
64 &uvscom_debug, 0, "Debug level");
65#endif
66
67#define UVSCOM_MODVER 1 /* module version */
68
69#define UVSCOM_CONFIG_INDEX 0
70#define UVSCOM_IFACE_INDEX 0
71
72/* Request */
73#define UVSCOM_SET_SPEED 0x10
74#define UVSCOM_LINE_CTL 0x11
75#define UVSCOM_SET_PARAM 0x12
76#define UVSCOM_READ_STATUS 0xd0
77#define UVSCOM_SHUTDOWN 0xe0
78
79/* UVSCOM_SET_SPEED parameters */
80#define UVSCOM_SPEED_150BPS 0x00
81#define UVSCOM_SPEED_300BPS 0x01
82#define UVSCOM_SPEED_600BPS 0x02
83#define UVSCOM_SPEED_1200BPS 0x03
84#define UVSCOM_SPEED_2400BPS 0x04
85#define UVSCOM_SPEED_4800BPS 0x05
86#define UVSCOM_SPEED_9600BPS 0x06
87#define UVSCOM_SPEED_19200BPS 0x07
88#define UVSCOM_SPEED_38400BPS 0x08
89#define UVSCOM_SPEED_57600BPS 0x09
90#define UVSCOM_SPEED_115200BPS 0x0a
91
92/* UVSCOM_LINE_CTL parameters */
93#define UVSCOM_BREAK 0x40
94#define UVSCOM_RTS 0x02
95#define UVSCOM_DTR 0x01
96#define UVSCOM_LINE_INIT 0x08
97
98/* UVSCOM_SET_PARAM parameters */
99#define UVSCOM_DATA_MASK 0x03
100#define UVSCOM_DATA_BIT_8 0x03
101#define UVSCOM_DATA_BIT_7 0x02
102#define UVSCOM_DATA_BIT_6 0x01
103#define UVSCOM_DATA_BIT_5 0x00
104
105#define UVSCOM_STOP_MASK 0x04
106#define UVSCOM_STOP_BIT_2 0x04
107#define UVSCOM_STOP_BIT_1 0x00
108
109#define UVSCOM_PARITY_MASK 0x18
110#define UVSCOM_PARITY_EVEN 0x18
111#define UVSCOM_PARITY_ODD 0x08
112#define UVSCOM_PARITY_NONE 0x00
113
114/* Status bits */
115#define UVSCOM_TXRDY 0x04
116#define UVSCOM_RXRDY 0x01
117
118#define UVSCOM_DCD 0x08
119#define UVSCOM_NOCARD 0x04
120#define UVSCOM_DSR 0x02
121#define UVSCOM_CTS 0x01
122#define UVSCOM_USTAT_MASK (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
123
124#define UVSCOM_BULK_BUF_SIZE 1024 /* bytes */
125
126#define UVSCOM_N_TRANSFER 6 /* units */
127
128struct uvscom_softc {
129 struct usb2_com_super_softc sc_super_ucom;
130 struct usb2_com_softc sc_ucom;
131
132 struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER];
133 struct usb2_device *sc_udev;
134
135 uint16_t sc_line; /* line control register */
136
137 uint8_t sc_flag;
138#define UVSCOM_FLAG_WRITE_STALL 0x0001
139#define UVSCOM_FLAG_READ_STALL 0x0002
140#define UVSCOM_FLAG_INTR_STALL 0x0004
141 uint8_t sc_iface_no; /* interface number */
142 uint8_t sc_iface_index; /* interface index */
143 uint8_t sc_lsr; /* local status register */
144 uint8_t sc_msr; /* uvscom status register */
145 uint8_t sc_unit_status; /* unit status */
146};
147
148/* prototypes */
149
150static device_probe_t uvscom_probe;
151static device_attach_t uvscom_attach;
152static device_detach_t uvscom_detach;
153
154static usb2_callback_t uvscom_write_callback;
155static usb2_callback_t uvscom_write_clear_stall_callback;
156static usb2_callback_t uvscom_read_callback;
157static usb2_callback_t uvscom_read_clear_stall_callback;
158static usb2_callback_t uvscom_intr_callback;
159static usb2_callback_t uvscom_intr_clear_stall_callback;
160
161static void uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
162static void uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t);
163static void uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t);
164static int uvscom_pre_param(struct usb2_com_softc *, struct termios *);
165static void uvscom_cfg_param(struct usb2_com_softc *, struct termios *);
166static int uvscom_pre_open(struct usb2_com_softc *);
167static void uvscom_cfg_open(struct usb2_com_softc *);
168static void uvscom_cfg_close(struct usb2_com_softc *);
169static void uvscom_start_read(struct usb2_com_softc *);
170static void uvscom_stop_read(struct usb2_com_softc *);
171static void uvscom_start_write(struct usb2_com_softc *);
172static void uvscom_stop_write(struct usb2_com_softc *);
173static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
174 uint8_t *);
175static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t);
176static uint16_t uvscom_cfg_read_status(struct uvscom_softc *);
177
178static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = {
179
180 [0] = {
181 .type = UE_BULK,
182 .endpoint = UE_ADDR_ANY,
183 .direction = UE_DIR_OUT,
184 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
185 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
186 .mh.callback = &uvscom_write_callback,
187 },
188
189 [1] = {
190 .type = UE_BULK,
191 .endpoint = UE_ADDR_ANY,
192 .direction = UE_DIR_IN,
193 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
194 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
195 .mh.callback = &uvscom_read_callback,
196 },
197
198 [2] = {
199 .type = UE_CONTROL,
200 .endpoint = 0x00, /* Control pipe */
201 .direction = UE_DIR_ANY,
202 .mh.bufsize = sizeof(struct usb2_device_request),
203 .mh.callback = &uvscom_write_clear_stall_callback,
204 .mh.timeout = 1000, /* 1 second */
205 .mh.interval = 50, /* 50ms */
206 },
207
208 [3] = {
209 .type = UE_CONTROL,
210 .endpoint = 0x00, /* Control pipe */
211 .direction = UE_DIR_ANY,
212 .mh.bufsize = sizeof(struct usb2_device_request),
213 .mh.callback = &uvscom_read_clear_stall_callback,
214 .mh.timeout = 1000, /* 1 second */
215 .mh.interval = 50, /* 50ms */
216 },
217
218 [4] = {
219 .type = UE_INTERRUPT,
220 .endpoint = UE_ADDR_ANY,
221 .direction = UE_DIR_IN,
222 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
223 .mh.bufsize = 0, /* use wMaxPacketSize */
224 .mh.callback = &uvscom_intr_callback,
225 },
226
227 [5] = {
228 .type = UE_CONTROL,
229 .endpoint = 0x00, /* Control pipe */
230 .direction = UE_DIR_ANY,
231 .mh.bufsize = sizeof(struct usb2_device_request),
232 .mh.callback = &uvscom_intr_clear_stall_callback,
233 .mh.timeout = 1000, /* 1 second */
234 .mh.interval = 50, /* 50ms */
235 },
236};
237
238static const struct usb2_com_callback uvscom_callback = {
239 .usb2_com_cfg_get_status = &uvscom_cfg_get_status,
240 .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr,
241 .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts,
242 .usb2_com_cfg_set_break = &uvscom_cfg_set_break,
243 .usb2_com_cfg_param = &uvscom_cfg_param,
244 .usb2_com_cfg_open = &uvscom_cfg_open,
245 .usb2_com_cfg_close = &uvscom_cfg_close,
246 .usb2_com_pre_open = &uvscom_pre_open,
247 .usb2_com_pre_param = &uvscom_pre_param,
248 .usb2_com_start_read = &uvscom_start_read,
249 .usb2_com_stop_read = &uvscom_stop_read,
250 .usb2_com_start_write = &uvscom_start_write,
251 .usb2_com_stop_write = &uvscom_stop_write,
252};
253
254static const struct usb2_device_id uvscom_devs[] = {
255 /* SUNTAC U-Cable type A4 */
256 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)},
257 /* SUNTAC U-Cable type D2 */
258 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)},
259 /* SUNTAC Ir-Trinity */
260 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)},
261 /* SUNTAC U-Cable type P1 */
262 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)},
263 /* SUNTAC Slipper U */
264 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)},
265};
266
267static device_method_t uvscom_methods[] = {
268 DEVMETHOD(device_probe, uvscom_probe),
269 DEVMETHOD(device_attach, uvscom_attach),
270 DEVMETHOD(device_detach, uvscom_detach),
271 {0, 0}
272};
273
274static devclass_t uvscom_devclass;
275
276static driver_t uvscom_driver = {
277 .name = "uvscom",
278 .methods = uvscom_methods,
279 .size = sizeof(struct uvscom_softc),
280};
281
282DRIVER_MODULE(uvscom, ushub, uvscom_driver, uvscom_devclass, NULL, 0);
283MODULE_DEPEND(uvscom, usb2_serial, 1, 1, 1);
284MODULE_DEPEND(uvscom, usb2_core, 1, 1, 1);
285MODULE_VERSION(uvscom, UVSCOM_MODVER);
286
287static int
288uvscom_probe(device_t dev)
289{
290 struct usb2_attach_arg *uaa = device_get_ivars(dev);
291
292 if (uaa->usb2_mode != USB_MODE_HOST) {
293 return (ENXIO);
294 }
295 if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) {
296 return (ENXIO);
297 }
298 if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) {
299 return (ENXIO);
300 }
301 return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa));
302}
303
304static int
305uvscom_attach(device_t dev)
306{
307 struct usb2_attach_arg *uaa = device_get_ivars(dev);
308 struct uvscom_softc *sc = device_get_softc(dev);
309 int error;
310
311 if (sc == NULL) {
312 return (ENOMEM);
313 }
314 device_set_usb2_desc(dev);
315
316 sc->sc_udev = uaa->device;
317
318 DPRINTF("sc=%p\n", sc);
319
320 sc->sc_iface_no = uaa->info.bIfaceNum;
321 sc->sc_iface_index = UVSCOM_IFACE_INDEX;
322
323 error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index,
324 sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &Giant);
325
326 if (error) {
327 DPRINTF("could not allocate all USB transfers!\n");
328 goto detach;
329 }
330 sc->sc_line = UVSCOM_LINE_INIT;
331
332 /* clear stall at first run */
333 sc->sc_flag |= (UVSCOM_FLAG_WRITE_STALL |
334 UVSCOM_FLAG_READ_STALL);
335
336 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
337 &uvscom_callback, &Giant);
338 if (error) {
339 goto detach;
340 }
341 /* start interrupt pipe */
342 mtx_lock(&Giant);
343 usb2_transfer_start(sc->sc_xfer[4]);
344 mtx_unlock(&Giant);
345
346 return (0);
347
348detach:
349 uvscom_detach(dev);
350 return (ENXIO);
351}
352
353static int
354uvscom_detach(device_t dev)
355{
356 struct uvscom_softc *sc = device_get_softc(dev);
357
358 DPRINTF("sc=%p\n", sc);
359
360 /* stop interrupt pipe */
361
362 if (sc->sc_xfer[4]) {
363 usb2_transfer_stop(sc->sc_xfer[4]);
364 }
365 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
366
367 usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER);
368
369 return (0);
370}
371
372static void
373uvscom_write_callback(struct usb2_xfer *xfer)
374{
375 struct uvscom_softc *sc = xfer->priv_sc;
376 uint32_t actlen;
377
378 switch (USB_GET_STATE(xfer)) {
379 case USB_ST_SETUP:
380 case USB_ST_TRANSFERRED:
381 if (sc->sc_flag & UVSCOM_FLAG_WRITE_STALL) {
382 usb2_transfer_start(sc->sc_xfer[2]);
383 return;
384 }
385 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
386 UVSCOM_BULK_BUF_SIZE, &actlen)) {
387
388 xfer->frlengths[0] = actlen;
389 usb2_start_hardware(xfer);
390 }
391 return;
392
393 default: /* Error */
394 if (xfer->error != USB_ERR_CANCELLED) {
395 sc->sc_flag |= UVSCOM_FLAG_WRITE_STALL;
396 usb2_transfer_start(sc->sc_xfer[2]);
397 }
398 return;
399
400 }
401}
402
403static void
404uvscom_write_clear_stall_callback(struct usb2_xfer *xfer)
405{
406 struct uvscom_softc *sc = xfer->priv_sc;
407 struct usb2_xfer *xfer_other = sc->sc_xfer[0];
408
409 if (usb2_clear_stall_callback(xfer, xfer_other)) {
410 DPRINTF("stall cleared\n");
411 sc->sc_flag &= ~UVSCOM_FLAG_WRITE_STALL;
412 usb2_transfer_start(xfer_other);
413 }
414}
415
416static void
417uvscom_read_callback(struct usb2_xfer *xfer)
418{
419 struct uvscom_softc *sc = xfer->priv_sc;
420
421 switch (USB_GET_STATE(xfer)) {
422 case USB_ST_TRANSFERRED:
423 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
424
425 case USB_ST_SETUP:
426 if (sc->sc_flag & UVSCOM_FLAG_READ_STALL) {
427 usb2_transfer_start(sc->sc_xfer[3]);
428 } else {
429 xfer->frlengths[0] = xfer->max_data_length;
430 usb2_start_hardware(xfer);
431 }
432 return;
433
434 default: /* Error */
435 if (xfer->error != USB_ERR_CANCELLED) {
436 sc->sc_flag |= UVSCOM_FLAG_READ_STALL;
437 usb2_transfer_start(sc->sc_xfer[3]);
438 }
439 return;
440
441 }
442}
443
444static void
445uvscom_read_clear_stall_callback(struct usb2_xfer *xfer)
446{
447 struct uvscom_softc *sc = xfer->priv_sc;
448 struct usb2_xfer *xfer_other = sc->sc_xfer[1];
449
450 if (usb2_clear_stall_callback(xfer, xfer_other)) {
451 DPRINTF("stall cleared\n");
452 sc->sc_flag &= ~UVSCOM_FLAG_READ_STALL;
453 usb2_transfer_start(xfer_other);
454 }
455}
456
457static void
458uvscom_intr_callback(struct usb2_xfer *xfer)
459{
460 struct uvscom_softc *sc = xfer->priv_sc;
461 uint8_t buf[2];
462
463 switch (USB_GET_STATE(xfer)) {
464 case USB_ST_TRANSFERRED:
465 if (xfer->actlen >= 2) {
466
467 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
468
469 sc->sc_lsr = 0;
470 sc->sc_msr = 0;
471 sc->sc_unit_status = buf[1];
472
473 if (buf[0] & UVSCOM_TXRDY) {
474 sc->sc_lsr |= ULSR_TXRDY;
475 }
476 if (buf[0] & UVSCOM_RXRDY) {
477 sc->sc_lsr |= ULSR_RXRDY;
478 }
479 if (buf[1] & UVSCOM_CTS) {
480 sc->sc_msr |= SER_CTS;
481 }
482 if (buf[1] & UVSCOM_DSR) {
483 sc->sc_msr |= SER_DSR;
484 }
485 if (buf[1] & UVSCOM_DCD) {
486 sc->sc_msr |= SER_DCD;
487 }
488 /*
489 * the UCOM layer will ignore this call if the TTY
490 * device is closed!
491 */
492 usb2_com_status_change(&sc->sc_ucom);
493 }
494 case USB_ST_SETUP:
495 if (sc->sc_flag & UVSCOM_FLAG_INTR_STALL) {
496 usb2_transfer_start(sc->sc_xfer[5]);
497 } else {
498 xfer->frlengths[0] = xfer->max_data_length;
499 usb2_start_hardware(xfer);
500 }
501 return;
502
503 default: /* Error */
504 if (xfer->error != USB_ERR_CANCELLED) {
505 sc->sc_flag |= UVSCOM_FLAG_INTR_STALL;
506 usb2_transfer_start(sc->sc_xfer[5]);
507 }
508 return;
509
510 }
511}
512
513static void
514uvscom_intr_clear_stall_callback(struct usb2_xfer *xfer)
515{
516 struct uvscom_softc *sc = xfer->priv_sc;
517 struct usb2_xfer *xfer_other = sc->sc_xfer[4];
518
519 if (usb2_clear_stall_callback(xfer, xfer_other)) {
520 DPRINTF("stall cleared\n");
521 sc->sc_flag &= ~UVSCOM_FLAG_INTR_STALL;
522 usb2_transfer_start(xfer_other);
523 }
524}
525
526static void
527uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
528{
529 struct uvscom_softc *sc = ucom->sc_parent;
530
531 DPRINTF("onoff = %d\n", onoff);
532
533 if (onoff)
534 sc->sc_line |= UVSCOM_DTR;
535 else
536 sc->sc_line &= ~UVSCOM_DTR;
537
538 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
539}
540
541static void
542uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
543{
544 struct uvscom_softc *sc = ucom->sc_parent;
545
546 DPRINTF("onoff = %d\n", onoff);
547
548 if (onoff)
549 sc->sc_line |= UVSCOM_RTS;
550 else
551 sc->sc_line &= ~UVSCOM_RTS;
552
553 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
554}
555
556static void
557uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
558{
559 struct uvscom_softc *sc = ucom->sc_parent;
560
561 DPRINTF("onoff = %d\n", onoff);
562
563 if (onoff)
564 sc->sc_line |= UVSCOM_BREAK;
565 else
566 sc->sc_line &= ~UVSCOM_BREAK;
567
568 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
569}
570
571static int
572uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
573{
574 switch (t->c_ospeed) {
575 case B150:
576 case B300:
577 case B600:
578 case B1200:
579 case B2400:
580 case B4800:
581 case B9600:
582 case B19200:
583 case B38400:
584 case B57600:
585 case B115200:
586 default:
587 return (EINVAL);
588 }
589 return (0);
590}
591
592static void
593uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
594{
595 struct uvscom_softc *sc = ucom->sc_parent;
596 uint16_t value;
597
598 DPRINTF("\n");
599
600 switch (t->c_ospeed) {
601 case B150:
602 value = UVSCOM_SPEED_150BPS;
603 break;
604 case B300:
605 value = UVSCOM_SPEED_300BPS;
606 break;
607 case B600:
608 value = UVSCOM_SPEED_600BPS;
609 break;
610 case B1200:
611 value = UVSCOM_SPEED_1200BPS;
612 break;
613 case B2400:
614 value = UVSCOM_SPEED_2400BPS;
615 break;
616 case B4800:
617 value = UVSCOM_SPEED_4800BPS;
618 break;
619 case B9600:
620 value = UVSCOM_SPEED_9600BPS;
621 break;
622 case B19200:
623 value = UVSCOM_SPEED_19200BPS;
624 break;
625 case B38400:
626 value = UVSCOM_SPEED_38400BPS;
627 break;
628 case B57600:
629 value = UVSCOM_SPEED_57600BPS;
630 break;
631 case B115200:
632 value = UVSCOM_SPEED_115200BPS;
633 break;
634 default:
635 return;
636 }
637
638 uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value);
639
640 value = 0;
641
642 if (t->c_cflag & CSTOPB) {
643 value |= UVSCOM_STOP_BIT_2;
644 }
645 if (t->c_cflag & PARENB) {
646 if (t->c_cflag & PARODD) {
647 value |= UVSCOM_PARITY_ODD;
648 } else {
649 value |= UVSCOM_PARITY_EVEN;
650 }
651 } else {
652 value |= UVSCOM_PARITY_NONE;
653 }
654
655 switch (t->c_cflag & CSIZE) {
656 case CS5:
657 value |= UVSCOM_DATA_BIT_5;
658 break;
659 case CS6:
660 value |= UVSCOM_DATA_BIT_6;
661 break;
662 case CS7:
663 value |= UVSCOM_DATA_BIT_7;
664 break;
665 default:
666 case CS8:
667 value |= UVSCOM_DATA_BIT_8;
668 break;
669 }
670
671 uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value);
672}
673
674static int
675uvscom_pre_open(struct usb2_com_softc *ucom)
676{
677 struct uvscom_softc *sc = ucom->sc_parent;
678
679 DPRINTF("sc = %p\n", sc);
680
681 /* check if PC card was inserted */
682
683 if (sc->sc_unit_status & UVSCOM_NOCARD) {
684 DPRINTF("no PC card!\n");
685 return (ENXIO);
686 }
687 return (0);
688}
689
690static void
691uvscom_cfg_open(struct usb2_com_softc *ucom)
692{
693 struct uvscom_softc *sc = ucom->sc_parent;
694
695 DPRINTF("sc = %p\n", sc);
696
697 uvscom_cfg_read_status(sc);
698}
699
700static void
701uvscom_cfg_close(struct usb2_com_softc *ucom)
702{
703 struct uvscom_softc *sc = ucom->sc_parent;
704
705 DPRINTF("sc=%p\n", sc);
706
707 uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0);
708}
709
710static void
711uvscom_start_read(struct usb2_com_softc *ucom)
712{
713 struct uvscom_softc *sc = ucom->sc_parent;
714
715 usb2_transfer_start(sc->sc_xfer[1]);
716}
717
718static void
719uvscom_stop_read(struct usb2_com_softc *ucom)
720{
721 struct uvscom_softc *sc = ucom->sc_parent;
722
723 usb2_transfer_stop(sc->sc_xfer[3]);
724 usb2_transfer_stop(sc->sc_xfer[1]);
725}
726
727static void
728uvscom_start_write(struct usb2_com_softc *ucom)
729{
730 struct uvscom_softc *sc = ucom->sc_parent;
731
732 usb2_transfer_start(sc->sc_xfer[0]);
733}
734
735static void
736uvscom_stop_write(struct usb2_com_softc *ucom)
737{
738 struct uvscom_softc *sc = ucom->sc_parent;
739
740 usb2_transfer_stop(sc->sc_xfer[2]);
741 usb2_transfer_stop(sc->sc_xfer[0]);
742}
743
744static void
745uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
746{
747 struct uvscom_softc *sc = ucom->sc_parent;
748
749 *lsr = sc->sc_lsr;
750 *msr = sc->sc_msr;
751}
752
753static void
754uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value)
755{
756 struct usb2_device_request req;
757 usb2_error_t err;
758
759 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
760 return;
761 }
762 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
763 req.bRequest = index;
764 USETW(req.wValue, value);
765 USETW(req.wIndex, 0);
766 USETW(req.wLength, 0);
767
768 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req,
769 NULL, 0, NULL, 1000);
770 if (err) {
771 DPRINTFN(0, "device request failed, err=%s "
772 "(ignored)\n", usb2_errstr(err));
773 }
774}
775
776static uint16_t
777uvscom_cfg_read_status(struct uvscom_softc *sc)
778{
779 struct usb2_device_request req;
780 usb2_error_t err;
781 uint8_t data[2];
782
783 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
784 return (0);
785 }
786 req.bmRequestType = UT_READ_VENDOR_DEVICE;
787 req.bRequest = UVSCOM_READ_STATUS;
788 USETW(req.wValue, 0);
789 USETW(req.wIndex, 0);
790 USETW(req.wLength, 2);
791
792 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req,
793 data, 0, NULL, 1000);
794 if (err) {
795 DPRINTFN(0, "device request failed, err=%s "
796 "(ignored)\n", usb2_errstr(err));
797 data[0] = 0;
798 data[1] = 0;
799 }
800 return (data[0] | (data[1] << 8));
801}
51#include <dev/usb2/core/usb2_request.h>
52#include <dev/usb2/core/usb2_lookup.h>
53#include <dev/usb2/core/usb2_util.h>
54#include <dev/usb2/core/usb2_busdma.h>
55
56#include <dev/usb2/serial/usb2_serial.h>
57
58#if USB_DEBUG
59static int uvscom_debug = 0;
60
61SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
62SYSCTL_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#define UVSCOM_N_TRANSFER 6 /* units */
126
127struct uvscom_softc {
128 struct usb2_com_super_softc sc_super_ucom;
129 struct usb2_com_softc sc_ucom;
130
131 struct usb2_xfer *sc_xfer[UVSCOM_N_TRANSFER];
132 struct usb2_device *sc_udev;
133
134 uint16_t sc_line; /* line control register */
135
136 uint8_t sc_flag;
137#define UVSCOM_FLAG_WRITE_STALL 0x0001
138#define UVSCOM_FLAG_READ_STALL 0x0002
139#define UVSCOM_FLAG_INTR_STALL 0x0004
140 uint8_t sc_iface_no; /* interface number */
141 uint8_t sc_iface_index; /* interface index */
142 uint8_t sc_lsr; /* local status register */
143 uint8_t sc_msr; /* uvscom status register */
144 uint8_t sc_unit_status; /* unit status */
145};
146
147/* prototypes */
148
149static device_probe_t uvscom_probe;
150static device_attach_t uvscom_attach;
151static device_detach_t uvscom_detach;
152
153static usb2_callback_t uvscom_write_callback;
154static usb2_callback_t uvscom_write_clear_stall_callback;
155static usb2_callback_t uvscom_read_callback;
156static usb2_callback_t uvscom_read_clear_stall_callback;
157static usb2_callback_t uvscom_intr_callback;
158static usb2_callback_t uvscom_intr_clear_stall_callback;
159
160static void uvscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
161static void uvscom_cfg_set_rts(struct usb2_com_softc *, uint8_t);
162static void uvscom_cfg_set_break(struct usb2_com_softc *, uint8_t);
163static int uvscom_pre_param(struct usb2_com_softc *, struct termios *);
164static void uvscom_cfg_param(struct usb2_com_softc *, struct termios *);
165static int uvscom_pre_open(struct usb2_com_softc *);
166static void uvscom_cfg_open(struct usb2_com_softc *);
167static void uvscom_cfg_close(struct usb2_com_softc *);
168static void uvscom_start_read(struct usb2_com_softc *);
169static void uvscom_stop_read(struct usb2_com_softc *);
170static void uvscom_start_write(struct usb2_com_softc *);
171static void uvscom_stop_write(struct usb2_com_softc *);
172static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
173 uint8_t *);
174static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t);
175static uint16_t uvscom_cfg_read_status(struct uvscom_softc *);
176
177static const struct usb2_config uvscom_config[UVSCOM_N_TRANSFER] = {
178
179 [0] = {
180 .type = UE_BULK,
181 .endpoint = UE_ADDR_ANY,
182 .direction = UE_DIR_OUT,
183 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
184 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
185 .mh.callback = &uvscom_write_callback,
186 },
187
188 [1] = {
189 .type = UE_BULK,
190 .endpoint = UE_ADDR_ANY,
191 .direction = UE_DIR_IN,
192 .mh.bufsize = UVSCOM_BULK_BUF_SIZE,
193 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
194 .mh.callback = &uvscom_read_callback,
195 },
196
197 [2] = {
198 .type = UE_CONTROL,
199 .endpoint = 0x00, /* Control pipe */
200 .direction = UE_DIR_ANY,
201 .mh.bufsize = sizeof(struct usb2_device_request),
202 .mh.callback = &uvscom_write_clear_stall_callback,
203 .mh.timeout = 1000, /* 1 second */
204 .mh.interval = 50, /* 50ms */
205 },
206
207 [3] = {
208 .type = UE_CONTROL,
209 .endpoint = 0x00, /* Control pipe */
210 .direction = UE_DIR_ANY,
211 .mh.bufsize = sizeof(struct usb2_device_request),
212 .mh.callback = &uvscom_read_clear_stall_callback,
213 .mh.timeout = 1000, /* 1 second */
214 .mh.interval = 50, /* 50ms */
215 },
216
217 [4] = {
218 .type = UE_INTERRUPT,
219 .endpoint = UE_ADDR_ANY,
220 .direction = UE_DIR_IN,
221 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
222 .mh.bufsize = 0, /* use wMaxPacketSize */
223 .mh.callback = &uvscom_intr_callback,
224 },
225
226 [5] = {
227 .type = UE_CONTROL,
228 .endpoint = 0x00, /* Control pipe */
229 .direction = UE_DIR_ANY,
230 .mh.bufsize = sizeof(struct usb2_device_request),
231 .mh.callback = &uvscom_intr_clear_stall_callback,
232 .mh.timeout = 1000, /* 1 second */
233 .mh.interval = 50, /* 50ms */
234 },
235};
236
237static const struct usb2_com_callback uvscom_callback = {
238 .usb2_com_cfg_get_status = &uvscom_cfg_get_status,
239 .usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr,
240 .usb2_com_cfg_set_rts = &uvscom_cfg_set_rts,
241 .usb2_com_cfg_set_break = &uvscom_cfg_set_break,
242 .usb2_com_cfg_param = &uvscom_cfg_param,
243 .usb2_com_cfg_open = &uvscom_cfg_open,
244 .usb2_com_cfg_close = &uvscom_cfg_close,
245 .usb2_com_pre_open = &uvscom_pre_open,
246 .usb2_com_pre_param = &uvscom_pre_param,
247 .usb2_com_start_read = &uvscom_start_read,
248 .usb2_com_stop_read = &uvscom_stop_read,
249 .usb2_com_start_write = &uvscom_start_write,
250 .usb2_com_stop_write = &uvscom_stop_write,
251};
252
253static const struct usb2_device_id uvscom_devs[] = {
254 /* SUNTAC U-Cable type A4 */
255 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)},
256 /* SUNTAC U-Cable type D2 */
257 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)},
258 /* SUNTAC Ir-Trinity */
259 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)},
260 /* SUNTAC U-Cable type P1 */
261 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)},
262 /* SUNTAC Slipper U */
263 {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)},
264};
265
266static device_method_t uvscom_methods[] = {
267 DEVMETHOD(device_probe, uvscom_probe),
268 DEVMETHOD(device_attach, uvscom_attach),
269 DEVMETHOD(device_detach, uvscom_detach),
270 {0, 0}
271};
272
273static devclass_t uvscom_devclass;
274
275static driver_t uvscom_driver = {
276 .name = "uvscom",
277 .methods = uvscom_methods,
278 .size = sizeof(struct uvscom_softc),
279};
280
281DRIVER_MODULE(uvscom, ushub, uvscom_driver, uvscom_devclass, NULL, 0);
282MODULE_DEPEND(uvscom, usb2_serial, 1, 1, 1);
283MODULE_DEPEND(uvscom, usb2_core, 1, 1, 1);
284MODULE_VERSION(uvscom, UVSCOM_MODVER);
285
286static int
287uvscom_probe(device_t dev)
288{
289 struct usb2_attach_arg *uaa = device_get_ivars(dev);
290
291 if (uaa->usb2_mode != USB_MODE_HOST) {
292 return (ENXIO);
293 }
294 if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) {
295 return (ENXIO);
296 }
297 if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) {
298 return (ENXIO);
299 }
300 return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa));
301}
302
303static int
304uvscom_attach(device_t dev)
305{
306 struct usb2_attach_arg *uaa = device_get_ivars(dev);
307 struct uvscom_softc *sc = device_get_softc(dev);
308 int error;
309
310 if (sc == NULL) {
311 return (ENOMEM);
312 }
313 device_set_usb2_desc(dev);
314
315 sc->sc_udev = uaa->device;
316
317 DPRINTF("sc=%p\n", sc);
318
319 sc->sc_iface_no = uaa->info.bIfaceNum;
320 sc->sc_iface_index = UVSCOM_IFACE_INDEX;
321
322 error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index,
323 sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &Giant);
324
325 if (error) {
326 DPRINTF("could not allocate all USB transfers!\n");
327 goto detach;
328 }
329 sc->sc_line = UVSCOM_LINE_INIT;
330
331 /* clear stall at first run */
332 sc->sc_flag |= (UVSCOM_FLAG_WRITE_STALL |
333 UVSCOM_FLAG_READ_STALL);
334
335 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
336 &uvscom_callback, &Giant);
337 if (error) {
338 goto detach;
339 }
340 /* start interrupt pipe */
341 mtx_lock(&Giant);
342 usb2_transfer_start(sc->sc_xfer[4]);
343 mtx_unlock(&Giant);
344
345 return (0);
346
347detach:
348 uvscom_detach(dev);
349 return (ENXIO);
350}
351
352static int
353uvscom_detach(device_t dev)
354{
355 struct uvscom_softc *sc = device_get_softc(dev);
356
357 DPRINTF("sc=%p\n", sc);
358
359 /* stop interrupt pipe */
360
361 if (sc->sc_xfer[4]) {
362 usb2_transfer_stop(sc->sc_xfer[4]);
363 }
364 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
365
366 usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER);
367
368 return (0);
369}
370
371static void
372uvscom_write_callback(struct usb2_xfer *xfer)
373{
374 struct uvscom_softc *sc = xfer->priv_sc;
375 uint32_t actlen;
376
377 switch (USB_GET_STATE(xfer)) {
378 case USB_ST_SETUP:
379 case USB_ST_TRANSFERRED:
380 if (sc->sc_flag & UVSCOM_FLAG_WRITE_STALL) {
381 usb2_transfer_start(sc->sc_xfer[2]);
382 return;
383 }
384 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
385 UVSCOM_BULK_BUF_SIZE, &actlen)) {
386
387 xfer->frlengths[0] = actlen;
388 usb2_start_hardware(xfer);
389 }
390 return;
391
392 default: /* Error */
393 if (xfer->error != USB_ERR_CANCELLED) {
394 sc->sc_flag |= UVSCOM_FLAG_WRITE_STALL;
395 usb2_transfer_start(sc->sc_xfer[2]);
396 }
397 return;
398
399 }
400}
401
402static void
403uvscom_write_clear_stall_callback(struct usb2_xfer *xfer)
404{
405 struct uvscom_softc *sc = xfer->priv_sc;
406 struct usb2_xfer *xfer_other = sc->sc_xfer[0];
407
408 if (usb2_clear_stall_callback(xfer, xfer_other)) {
409 DPRINTF("stall cleared\n");
410 sc->sc_flag &= ~UVSCOM_FLAG_WRITE_STALL;
411 usb2_transfer_start(xfer_other);
412 }
413}
414
415static void
416uvscom_read_callback(struct usb2_xfer *xfer)
417{
418 struct uvscom_softc *sc = xfer->priv_sc;
419
420 switch (USB_GET_STATE(xfer)) {
421 case USB_ST_TRANSFERRED:
422 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
423
424 case USB_ST_SETUP:
425 if (sc->sc_flag & UVSCOM_FLAG_READ_STALL) {
426 usb2_transfer_start(sc->sc_xfer[3]);
427 } else {
428 xfer->frlengths[0] = xfer->max_data_length;
429 usb2_start_hardware(xfer);
430 }
431 return;
432
433 default: /* Error */
434 if (xfer->error != USB_ERR_CANCELLED) {
435 sc->sc_flag |= UVSCOM_FLAG_READ_STALL;
436 usb2_transfer_start(sc->sc_xfer[3]);
437 }
438 return;
439
440 }
441}
442
443static void
444uvscom_read_clear_stall_callback(struct usb2_xfer *xfer)
445{
446 struct uvscom_softc *sc = xfer->priv_sc;
447 struct usb2_xfer *xfer_other = sc->sc_xfer[1];
448
449 if (usb2_clear_stall_callback(xfer, xfer_other)) {
450 DPRINTF("stall cleared\n");
451 sc->sc_flag &= ~UVSCOM_FLAG_READ_STALL;
452 usb2_transfer_start(xfer_other);
453 }
454}
455
456static void
457uvscom_intr_callback(struct usb2_xfer *xfer)
458{
459 struct uvscom_softc *sc = xfer->priv_sc;
460 uint8_t buf[2];
461
462 switch (USB_GET_STATE(xfer)) {
463 case USB_ST_TRANSFERRED:
464 if (xfer->actlen >= 2) {
465
466 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
467
468 sc->sc_lsr = 0;
469 sc->sc_msr = 0;
470 sc->sc_unit_status = buf[1];
471
472 if (buf[0] & UVSCOM_TXRDY) {
473 sc->sc_lsr |= ULSR_TXRDY;
474 }
475 if (buf[0] & UVSCOM_RXRDY) {
476 sc->sc_lsr |= ULSR_RXRDY;
477 }
478 if (buf[1] & UVSCOM_CTS) {
479 sc->sc_msr |= SER_CTS;
480 }
481 if (buf[1] & UVSCOM_DSR) {
482 sc->sc_msr |= SER_DSR;
483 }
484 if (buf[1] & UVSCOM_DCD) {
485 sc->sc_msr |= SER_DCD;
486 }
487 /*
488 * the UCOM layer will ignore this call if the TTY
489 * device is closed!
490 */
491 usb2_com_status_change(&sc->sc_ucom);
492 }
493 case USB_ST_SETUP:
494 if (sc->sc_flag & UVSCOM_FLAG_INTR_STALL) {
495 usb2_transfer_start(sc->sc_xfer[5]);
496 } else {
497 xfer->frlengths[0] = xfer->max_data_length;
498 usb2_start_hardware(xfer);
499 }
500 return;
501
502 default: /* Error */
503 if (xfer->error != USB_ERR_CANCELLED) {
504 sc->sc_flag |= UVSCOM_FLAG_INTR_STALL;
505 usb2_transfer_start(sc->sc_xfer[5]);
506 }
507 return;
508
509 }
510}
511
512static void
513uvscom_intr_clear_stall_callback(struct usb2_xfer *xfer)
514{
515 struct uvscom_softc *sc = xfer->priv_sc;
516 struct usb2_xfer *xfer_other = sc->sc_xfer[4];
517
518 if (usb2_clear_stall_callback(xfer, xfer_other)) {
519 DPRINTF("stall cleared\n");
520 sc->sc_flag &= ~UVSCOM_FLAG_INTR_STALL;
521 usb2_transfer_start(xfer_other);
522 }
523}
524
525static void
526uvscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
527{
528 struct uvscom_softc *sc = ucom->sc_parent;
529
530 DPRINTF("onoff = %d\n", onoff);
531
532 if (onoff)
533 sc->sc_line |= UVSCOM_DTR;
534 else
535 sc->sc_line &= ~UVSCOM_DTR;
536
537 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
538}
539
540static void
541uvscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
542{
543 struct uvscom_softc *sc = ucom->sc_parent;
544
545 DPRINTF("onoff = %d\n", onoff);
546
547 if (onoff)
548 sc->sc_line |= UVSCOM_RTS;
549 else
550 sc->sc_line &= ~UVSCOM_RTS;
551
552 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
553}
554
555static void
556uvscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
557{
558 struct uvscom_softc *sc = ucom->sc_parent;
559
560 DPRINTF("onoff = %d\n", onoff);
561
562 if (onoff)
563 sc->sc_line |= UVSCOM_BREAK;
564 else
565 sc->sc_line &= ~UVSCOM_BREAK;
566
567 uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
568}
569
570static int
571uvscom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
572{
573 switch (t->c_ospeed) {
574 case B150:
575 case B300:
576 case B600:
577 case B1200:
578 case B2400:
579 case B4800:
580 case B9600:
581 case B19200:
582 case B38400:
583 case B57600:
584 case B115200:
585 default:
586 return (EINVAL);
587 }
588 return (0);
589}
590
591static void
592uvscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
593{
594 struct uvscom_softc *sc = ucom->sc_parent;
595 uint16_t value;
596
597 DPRINTF("\n");
598
599 switch (t->c_ospeed) {
600 case B150:
601 value = UVSCOM_SPEED_150BPS;
602 break;
603 case B300:
604 value = UVSCOM_SPEED_300BPS;
605 break;
606 case B600:
607 value = UVSCOM_SPEED_600BPS;
608 break;
609 case B1200:
610 value = UVSCOM_SPEED_1200BPS;
611 break;
612 case B2400:
613 value = UVSCOM_SPEED_2400BPS;
614 break;
615 case B4800:
616 value = UVSCOM_SPEED_4800BPS;
617 break;
618 case B9600:
619 value = UVSCOM_SPEED_9600BPS;
620 break;
621 case B19200:
622 value = UVSCOM_SPEED_19200BPS;
623 break;
624 case B38400:
625 value = UVSCOM_SPEED_38400BPS;
626 break;
627 case B57600:
628 value = UVSCOM_SPEED_57600BPS;
629 break;
630 case B115200:
631 value = UVSCOM_SPEED_115200BPS;
632 break;
633 default:
634 return;
635 }
636
637 uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value);
638
639 value = 0;
640
641 if (t->c_cflag & CSTOPB) {
642 value |= UVSCOM_STOP_BIT_2;
643 }
644 if (t->c_cflag & PARENB) {
645 if (t->c_cflag & PARODD) {
646 value |= UVSCOM_PARITY_ODD;
647 } else {
648 value |= UVSCOM_PARITY_EVEN;
649 }
650 } else {
651 value |= UVSCOM_PARITY_NONE;
652 }
653
654 switch (t->c_cflag & CSIZE) {
655 case CS5:
656 value |= UVSCOM_DATA_BIT_5;
657 break;
658 case CS6:
659 value |= UVSCOM_DATA_BIT_6;
660 break;
661 case CS7:
662 value |= UVSCOM_DATA_BIT_7;
663 break;
664 default:
665 case CS8:
666 value |= UVSCOM_DATA_BIT_8;
667 break;
668 }
669
670 uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value);
671}
672
673static int
674uvscom_pre_open(struct usb2_com_softc *ucom)
675{
676 struct uvscom_softc *sc = ucom->sc_parent;
677
678 DPRINTF("sc = %p\n", sc);
679
680 /* check if PC card was inserted */
681
682 if (sc->sc_unit_status & UVSCOM_NOCARD) {
683 DPRINTF("no PC card!\n");
684 return (ENXIO);
685 }
686 return (0);
687}
688
689static void
690uvscom_cfg_open(struct usb2_com_softc *ucom)
691{
692 struct uvscom_softc *sc = ucom->sc_parent;
693
694 DPRINTF("sc = %p\n", sc);
695
696 uvscom_cfg_read_status(sc);
697}
698
699static void
700uvscom_cfg_close(struct usb2_com_softc *ucom)
701{
702 struct uvscom_softc *sc = ucom->sc_parent;
703
704 DPRINTF("sc=%p\n", sc);
705
706 uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0);
707}
708
709static void
710uvscom_start_read(struct usb2_com_softc *ucom)
711{
712 struct uvscom_softc *sc = ucom->sc_parent;
713
714 usb2_transfer_start(sc->sc_xfer[1]);
715}
716
717static void
718uvscom_stop_read(struct usb2_com_softc *ucom)
719{
720 struct uvscom_softc *sc = ucom->sc_parent;
721
722 usb2_transfer_stop(sc->sc_xfer[3]);
723 usb2_transfer_stop(sc->sc_xfer[1]);
724}
725
726static void
727uvscom_start_write(struct usb2_com_softc *ucom)
728{
729 struct uvscom_softc *sc = ucom->sc_parent;
730
731 usb2_transfer_start(sc->sc_xfer[0]);
732}
733
734static void
735uvscom_stop_write(struct usb2_com_softc *ucom)
736{
737 struct uvscom_softc *sc = ucom->sc_parent;
738
739 usb2_transfer_stop(sc->sc_xfer[2]);
740 usb2_transfer_stop(sc->sc_xfer[0]);
741}
742
743static void
744uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
745{
746 struct uvscom_softc *sc = ucom->sc_parent;
747
748 *lsr = sc->sc_lsr;
749 *msr = sc->sc_msr;
750}
751
752static void
753uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value)
754{
755 struct usb2_device_request req;
756 usb2_error_t err;
757
758 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
759 return;
760 }
761 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
762 req.bRequest = index;
763 USETW(req.wValue, value);
764 USETW(req.wIndex, 0);
765 USETW(req.wLength, 0);
766
767 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req,
768 NULL, 0, NULL, 1000);
769 if (err) {
770 DPRINTFN(0, "device request failed, err=%s "
771 "(ignored)\n", usb2_errstr(err));
772 }
773}
774
775static uint16_t
776uvscom_cfg_read_status(struct uvscom_softc *sc)
777{
778 struct usb2_device_request req;
779 usb2_error_t err;
780 uint8_t data[2];
781
782 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
783 return (0);
784 }
785 req.bmRequestType = UT_READ_VENDOR_DEVICE;
786 req.bRequest = UVSCOM_READ_STATUS;
787 USETW(req.wValue, 0);
788 USETW(req.wIndex, 0);
789 USETW(req.wLength, 2);
790
791 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req,
792 data, 0, NULL, 1000);
793 if (err) {
794 DPRINTFN(0, "device request failed, err=%s "
795 "(ignored)\n", usb2_errstr(err));
796 data[0] = 0;
797 data[1] = 0;
798 }
799 return (data[0] | (data[1] << 8));
800}