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