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