xref: /openbsd-src/sys/dev/usb/ucom.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: ucom.c,v 1.18 2003/05/19 00:33:00 nate Exp $ */
2 /*	$NetBSD: ucom.c,v 1.49 2003/01/01 00:10:25 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (lennart@augustsson.net) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 /*
41  * This code is very heavily based on the 16550 driver, com.c.
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/ioctl.h>
48 #include <sys/conf.h>
49 #include <sys/tty.h>
50 #include <sys/file.h>
51 #include <sys/select.h>
52 #include <sys/proc.h>
53 #include <sys/vnode.h>
54 #include <sys/device.h>
55 #include <sys/poll.h>
56 #if defined(__NetBSD__)
57 #include "rnd.h"
58 #if NRND > 0
59 #include <sys/rnd.h>
60 #endif
61 #endif
62 
63 #include <dev/usb/usb.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 #include "ucom.h"
73 
74 #if NUCOM > 0
75 
76 #ifdef UCOM_DEBUG
77 #define DPRINTFN(n, x)	if (ucomdebug > (n)) logprintf x
78 int ucomdebug = 0;
79 #else
80 #define DPRINTFN(n, x)
81 #endif
82 #define DPRINTF(x) DPRINTFN(0, x)
83 
84 #if defined(__NetBSD__)
85 #define	UCOMUNIT_MASK		0x3ffff
86 #define	UCOMDIALOUT_MASK	0x80000
87 #define	UCOMCALLUNIT_MASK	0x40000
88 
89 #define LINESW(tp, func)	((tp)->t_linesw->func)
90 #endif
91 
92 #if defined(__OpenBSD__)
93 #define	UCOMUNIT_MASK		0x3f
94 #define	UCOMDIALOUT_MASK	0x80
95 #define	UCOMCALLUNIT_MASK	0x40
96 
97 #define LINESW(tp, func)	(linesw[(tp)->t_line].func)
98 #endif
99 
100 #define	UCOMUNIT(x)		(minor(x) & UCOMUNIT_MASK)
101 #define	UCOMDIALOUT(x)		(minor(x) & UCOMDIALOUT_MASK)
102 #define	UCOMCALLUNIT(x)		(minor(x) & UCOMCALLUNIT_MASK)
103 
104 struct ucom_softc {
105 	USBBASEDEVICE		sc_dev;		/* base device */
106 
107 	usbd_device_handle	sc_udev;	/* USB device */
108 
109 	usbd_interface_handle	sc_iface;	/* data interface */
110 
111 	int			sc_bulkin_no;	/* bulk in endpoint address */
112 	usbd_pipe_handle	sc_bulkin_pipe;	/* bulk in pipe */
113 	usbd_xfer_handle	sc_ixfer;	/* read request */
114 	u_char			*sc_ibuf;	/* read buffer */
115 	u_int			sc_ibufsize;	/* read buffer size */
116 	u_int			sc_ibufsizepad;	/* read buffer size padded */
117 
118 	int			sc_bulkout_no;	/* bulk out endpoint address */
119 	usbd_pipe_handle	sc_bulkout_pipe;/* bulk out pipe */
120 	usbd_xfer_handle	sc_oxfer;	/* write request */
121 	u_char			*sc_obuf;	/* write buffer */
122 	u_int			sc_obufsize;	/* write buffer size */
123 	u_int			sc_opkthdrlen;	/* header length of
124 						 * output packet */
125 
126 	struct ucom_methods     *sc_methods;
127 	void                    *sc_parent;
128 	int			sc_portno;
129 
130 	struct tty		*sc_tty;	/* our tty */
131 	u_char			sc_lsr;
132 	u_char			sc_msr;
133 	u_char			sc_mcr;
134 	u_char			sc_tx_stopped;
135 	int			sc_swflags;
136 
137 	u_char			sc_opening;	/* lock during open */
138 	int			sc_refcnt;
139 	u_char			sc_dying;	/* disconnecting */
140 
141 #if defined(__NetBSD__) && NRND > 0
142 	rndsource_element_t	sc_rndsource;	/* random source */
143 #endif
144 };
145 
146 #if defined(__NetBSD__)
147 dev_type_open(ucomopen);
148 dev_type_close(ucomclose);
149 dev_type_read(ucomread);
150 dev_type_write(ucomwrite);
151 dev_type_ioctl(ucomioctl);
152 dev_type_stop(ucomstop);
153 dev_type_tty(ucomtty);
154 dev_type_poll(ucompoll);
155 
156 const struct cdevsw ucom_cdevsw = {
157 	ucomopen, ucomclose, ucomread, ucomwrite, ucomioctl,
158 	ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY
159 };
160 #endif
161 
162 Static void	ucom_cleanup(struct ucom_softc *);
163 Static void	ucom_hwiflow(struct ucom_softc *);
164 Static int	ucomparam(struct tty *, struct termios *);
165 Static void	ucomstart(struct tty *);
166 Static void	ucom_shutdown(struct ucom_softc *);
167 Static int	ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
168 			      int, usb_proc_ptr);
169 Static void	ucom_dtr(struct ucom_softc *, int);
170 Static void	ucom_rts(struct ucom_softc *, int);
171 Static void	ucom_break(struct ucom_softc *, int);
172 Static usbd_status ucomstartread(struct ucom_softc *);
173 Static void	ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
174 Static void	ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
175 Static void	tiocm_to_ucom(struct ucom_softc *, u_long, int);
176 Static int	ucom_to_tiocm(struct ucom_softc *);
177 
178 USB_DECLARE_DRIVER(ucom);
179 
180 USB_MATCH(ucom)
181 {
182 	return (1);
183 }
184 
185 USB_ATTACH(ucom)
186 {
187 	struct ucom_softc *sc = (struct ucom_softc *)self;
188 	struct ucom_attach_args *uca = aux;
189 	struct tty *tp;
190 
191 	if (uca->portno != UCOM_UNK_PORTNO)
192 		printf(": portno %d", uca->portno);
193 	if (uca->info != NULL)
194 		printf(", %s", uca->info);
195 	printf("\n");
196 
197 	sc->sc_udev = uca->device;
198 	sc->sc_iface = uca->iface;
199 	sc->sc_bulkout_no = uca->bulkout;
200 	sc->sc_bulkin_no = uca->bulkin;
201 	sc->sc_ibufsize = uca->ibufsize;
202 	sc->sc_ibufsizepad = uca->ibufsizepad;
203 	sc->sc_obufsize = uca->obufsize;
204 	sc->sc_opkthdrlen = uca->opkthdrlen;
205 	sc->sc_methods = uca->methods;
206 	sc->sc_parent = uca->arg;
207 	sc->sc_portno = uca->portno;
208 
209 	tp = ttymalloc();
210 	tp->t_oproc = ucomstart;
211 	tp->t_param = ucomparam;
212 	sc->sc_tty = tp;
213 
214 	DPRINTF(("ucom_attach: tty_attach %p\n", tp));
215 	tty_attach(tp);
216 
217 #if defined(__NetBSD__) && NRND > 0
218 	rnd_attach_source(&sc->sc_rndsource, USBDEVNAME(sc->sc_dev),
219 			  RND_TYPE_TTY, 0);
220 #endif
221 
222 	USB_ATTACH_SUCCESS_RETURN;
223 }
224 
225 USB_DETACH(ucom)
226 {
227 	struct ucom_softc *sc = (struct ucom_softc *)self;
228 	struct tty *tp = sc->sc_tty;
229 	int maj, mn;
230 	int s;
231 
232 	DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
233 		 sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
234 
235 	sc->sc_dying = 1;
236 
237 	if (sc->sc_bulkin_pipe != NULL)
238 		usbd_abort_pipe(sc->sc_bulkin_pipe);
239 	if (sc->sc_bulkout_pipe != NULL)
240 		usbd_abort_pipe(sc->sc_bulkout_pipe);
241 
242 	s = splusb();
243 	if (--sc->sc_refcnt >= 0) {
244 		/* Wake up anyone waiting */
245 		if (tp != NULL) {
246 			CLR(tp->t_state, TS_CARR_ON);
247 			CLR(tp->t_cflag, CLOCAL | MDMBUF);
248 			ttyflush(tp, FREAD|FWRITE);
249 		}
250 		/* Wait for processes to go away. */
251 		usb_detach_wait(USBDEV(sc->sc_dev));
252 	}
253 	splx(s);
254 
255 #if defined(__NetBSD__)
256 	/* locate the major number */
257 	maj = cdevsw_lookup_major(&ucom_cdevsw);
258 #else
259 	/* locate the major number */
260 	for (maj = 0; maj < nchrdev; maj++)
261 		if (cdevsw[maj].d_open == ucomopen)
262 			break;
263 #endif
264 
265 	/* Nuke the vnodes for any open instances. */
266 	mn = self->dv_unit;
267 	DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
268 	vdevgone(maj, mn, mn, VCHR);
269 	vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
270 	vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
271 
272 	/* Detach and free the tty. */
273 	if (tp != NULL) {
274 		tty_detach(tp);
275 		ttyfree(tp);
276 		sc->sc_tty = NULL;
277 	}
278 
279 	/* Detach the random source */
280 #if defined(__NetBSD__) && NRND > 0
281 	rnd_detach_source(&sc->sc_rndsource);
282 #endif
283 
284 	return (0);
285 }
286 
287 int
288 ucom_activate(device_ptr_t self, enum devact act)
289 {
290 	struct ucom_softc *sc = (struct ucom_softc *)self;
291 
292 	DPRINTFN(5,("ucom_activate: %d\n", act));
293 
294 	switch (act) {
295 	case DVACT_ACTIVATE:
296 		return (EOPNOTSUPP);
297 
298 	case DVACT_DEACTIVATE:
299 		sc->sc_dying = 1;
300 		break;
301 	}
302 	return (0);
303 }
304 
305 void
306 ucom_shutdown(struct ucom_softc *sc)
307 {
308 	struct tty *tp = sc->sc_tty;
309 
310 	DPRINTF(("ucom_shutdown\n"));
311 	/*
312 	 * Hang up if necessary.  Wait a bit, so the other side has time to
313 	 * notice even if we immediately open the port again.
314 	 */
315 	if (ISSET(tp->t_cflag, HUPCL)) {
316 		ucom_dtr(sc, 0);
317 		(void)tsleep(sc, TTIPRI, ttclos, hz);
318 	}
319 }
320 
321 int
322 ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
323 {
324 	int unit = UCOMUNIT(dev);
325 	usbd_status err;
326 	struct ucom_softc *sc;
327 	struct tty *tp;
328 	int s;
329 	int error;
330 
331 	if (unit >= ucom_cd.cd_ndevs)
332 		return (ENXIO);
333 	sc = ucom_cd.cd_devs[unit];
334 	if (sc == NULL)
335 		return (ENXIO);
336 
337 	if (sc->sc_dying)
338 		return (EIO);
339 
340 	if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
341 		return (ENXIO);
342 
343 	tp = sc->sc_tty;
344 
345 	DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
346 
347 	if (ISSET(tp->t_state, TS_ISOPEN) &&
348 	    ISSET(tp->t_state, TS_XCLUDE) &&
349 	    p->p_ucred->cr_uid != 0)
350 		return (EBUSY);
351 
352 	s = spltty();
353 
354 	/*
355 	 * Do the following iff this is a first open.
356 	 */
357 	while (sc->sc_opening)
358 		tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
359 
360 	if (sc->sc_dying) {
361 		splx(s);
362 		return (EIO);
363 	}
364 	sc->sc_opening = 1;
365 
366 #if defined(__NetBSD__)
367 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
368 #else
369 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
370 #endif
371 		struct termios t;
372 
373 		tp->t_dev = dev;
374 
375 		if (sc->sc_methods->ucom_open != NULL) {
376 			error = sc->sc_methods->ucom_open(sc->sc_parent,
377 							  sc->sc_portno);
378 			if (error) {
379 				ucom_cleanup(sc);
380 				sc->sc_opening = 0;
381 				wakeup(&sc->sc_opening);
382 				splx(s);
383 				return (error);
384 			}
385 		}
386 
387 		ucom_status_change(sc);
388 
389 		/*
390 		 * Initialize the termios status to the defaults.  Add in the
391 		 * sticky bits from TIOCSFLAGS.
392 		 */
393 		t.c_ispeed = 0;
394 		t.c_ospeed = TTYDEF_SPEED;
395 		t.c_cflag = TTYDEF_CFLAG;
396 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
397 			SET(t.c_cflag, CLOCAL);
398 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
399 			SET(t.c_cflag, CRTSCTS);
400 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
401 			SET(t.c_cflag, MDMBUF);
402 		/* Make sure ucomparam() will do something. */
403 		tp->t_ospeed = 0;
404 		(void) ucomparam(tp, &t);
405 		tp->t_iflag = TTYDEF_IFLAG;
406 		tp->t_oflag = TTYDEF_OFLAG;
407 		tp->t_lflag = TTYDEF_LFLAG;
408 		ttychars(tp);
409 		ttsetwater(tp);
410 
411 		/*
412 		 * Turn on DTR.  We must always do this, even if carrier is not
413 		 * present, because otherwise we'd have to use TIOCSDTR
414 		 * immediately after setting CLOCAL, which applications do not
415 		 * expect.  We always assert DTR while the device is open
416 		 * unless explicitly requested to deassert it.
417 		 */
418 		ucom_dtr(sc, 1);
419 
420 		/* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
421 		ucom_hwiflow(sc);
422 
423 		DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
424 			 sc->sc_bulkin_no, sc->sc_bulkout_no));
425 
426 		/* Open the bulk pipes */
427 		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
428 				     &sc->sc_bulkin_pipe);
429 		if (err) {
430 			DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
431 				 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
432 				 usbd_errstr(err)));
433 			error = EIO;
434 			goto fail_0;
435 		}
436 		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
437 				     USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
438 		if (err) {
439 			DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
440 				 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
441 				 usbd_errstr(err)));
442 			error = EIO;
443 			goto fail_1;
444 		}
445 
446 		/* Allocate a request and an input buffer and start reading. */
447 		sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
448 		if (sc->sc_ixfer == NULL) {
449 			error = ENOMEM;
450 			goto fail_2;
451 		}
452 
453 		sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
454 						sc->sc_ibufsizepad);
455 		if (sc->sc_ibuf == NULL) {
456 			error = ENOMEM;
457 			goto fail_3;
458 		}
459 
460 		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
461 		if (sc->sc_oxfer == NULL) {
462 			error = ENOMEM;
463 			goto fail_3;
464 		}
465 
466 		sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
467 						sc->sc_obufsize +
468 						sc->sc_opkthdrlen);
469 		if (sc->sc_obuf == NULL) {
470 			error = ENOMEM;
471 			goto fail_4;
472 		}
473 
474 		ucomstartread(sc);
475 	}
476 	sc->sc_opening = 0;
477 	wakeup(&sc->sc_opening);
478 	splx(s);
479 
480 #if defined(__NetBSD__)
481 	error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
482 #else
483 	error = ttyopen(UCOMDIALOUT(dev), tp);
484 #endif
485 	if (error)
486 		goto bad;
487 
488 	error = (*LINESW(tp, l_open))(dev, tp);
489 	if (error)
490 		goto bad;
491 
492 	return (0);
493 
494 fail_4:
495 	usbd_free_xfer(sc->sc_oxfer);
496 	sc->sc_oxfer = NULL;
497 fail_3:
498 	usbd_free_xfer(sc->sc_ixfer);
499 	sc->sc_ixfer = NULL;
500 fail_2:
501 	usbd_close_pipe(sc->sc_bulkout_pipe);
502 	sc->sc_bulkout_pipe = NULL;
503 fail_1:
504 	usbd_close_pipe(sc->sc_bulkin_pipe);
505 	sc->sc_bulkin_pipe = NULL;
506 fail_0:
507 	sc->sc_opening = 0;
508 	wakeup(&sc->sc_opening);
509 	splx(s);
510 	return (error);
511 
512 bad:
513 #if defined(__NetBSD__)
514 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
515 #else
516 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
517 #endif
518 		/*
519 		 * We failed to open the device, and nobody else had it opened.
520 		 * Clean up the state as appropriate.
521 		 */
522 		ucom_cleanup(sc);
523 	}
524 
525 	return (error);
526 }
527 
528 int
529 ucomclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
530 {
531 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
532 	struct tty *tp = sc->sc_tty;
533 
534 	DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
535 	if (!ISSET(tp->t_state, TS_ISOPEN))
536 		return (0);
537 
538 	sc->sc_refcnt++;
539 
540 	(*LINESW(tp, l_close))(tp, flag);
541 	ttyclose(tp);
542 
543 #if defined(__NetBSD__)
544 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
545 #else
546 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
547 #endif
548 		/*
549 		 * Although we got a last close, the device may still be in
550 		 * use; e.g. if this was the dialout node, and there are still
551 		 * processes waiting for carrier on the non-dialout node.
552 		 */
553 		ucom_cleanup(sc);
554 	}
555 
556 	if (sc->sc_methods->ucom_close != NULL)
557 		sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
558 
559 	if (--sc->sc_refcnt < 0)
560 		usb_detach_wakeup(USBDEV(sc->sc_dev));
561 
562 	return (0);
563 }
564 
565 int
566 ucomread(dev_t dev, struct uio *uio, int flag)
567 {
568 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
569 	struct tty *tp = sc->sc_tty;
570 	int error;
571 
572 	if (sc->sc_dying)
573 		return (EIO);
574 
575 	sc->sc_refcnt++;
576 	error = (*LINESW(tp, l_read))(tp, uio, flag);
577 	if (--sc->sc_refcnt < 0)
578 		usb_detach_wakeup(USBDEV(sc->sc_dev));
579 	return (error);
580 }
581 
582 int
583 ucomwrite(dev_t dev, struct uio *uio, int flag)
584 {
585 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
586 	struct tty *tp = sc->sc_tty;
587 	int error;
588 
589 	if (sc->sc_dying)
590 		return (EIO);
591 
592 	sc->sc_refcnt++;
593 	error = (*LINESW(tp, l_write))(tp, uio, flag);
594 	if (--sc->sc_refcnt < 0)
595 		usb_detach_wakeup(USBDEV(sc->sc_dev));
596 	return (error);
597 }
598 
599 #if defined(__NetBSD__)
600 int
601 ucompoll(dev_t dev, int events, usb_proc_ptr p)
602 {
603 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
604 	struct tty *tp = sc->sc_tty;
605 	int error;
606 
607 	if (sc->sc_dying)
608 		return (EIO);
609 
610 	sc->sc_refcnt++;
611 	error = (*LINESW(tp, l_poll))(tp, events, p);
612 	if (--sc->sc_refcnt < 0)
613 		usb_detach_wakeup(USBDEV(sc->sc_dev));
614 	return (error);
615 }
616 #endif
617 
618 struct tty *
619 ucomtty(dev_t dev)
620 {
621 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
622 	struct tty *tp = sc->sc_tty;
623 
624 	return (tp);
625 }
626 
627 int
628 ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
629 {
630 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
631 	int error;
632 
633 	sc->sc_refcnt++;
634 	error = ucom_do_ioctl(sc, cmd, data, flag, p);
635 	if (--sc->sc_refcnt < 0)
636 		usb_detach_wakeup(USBDEV(sc->sc_dev));
637 	return (error);
638 }
639 
640 Static int
641 ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
642 	      int flag, usb_proc_ptr p)
643 {
644 	struct tty *tp = sc->sc_tty;
645 	int error;
646 	int s;
647 
648 	if (sc->sc_dying)
649 		return (EIO);
650 
651 	DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
652 
653 	error = (*LINESW(tp, l_ioctl))(tp, cmd, data, flag, p);
654 	if (error >= 0)
655 		return (error);
656 
657 	error = ttioctl(tp, cmd, data, flag, p);
658 	if (error >= 0)
659 		return (error);
660 
661 	if (sc->sc_methods->ucom_ioctl != NULL) {
662 		error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
663 			    sc->sc_portno, cmd, data, flag, p);
664 		if (error >= 0)
665 			return (error);
666 	}
667 
668 	error = 0;
669 
670 	DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
671 	s = spltty();
672 
673 	switch (cmd) {
674 	case TIOCSBRK:
675 		ucom_break(sc, 1);
676 		break;
677 
678 	case TIOCCBRK:
679 		ucom_break(sc, 0);
680 		break;
681 
682 	case TIOCSDTR:
683 		ucom_dtr(sc, 1);
684 		break;
685 
686 	case TIOCCDTR:
687 		ucom_dtr(sc, 0);
688 		break;
689 
690 	case TIOCGFLAGS:
691 		*(int *)data = sc->sc_swflags;
692 		break;
693 
694 	case TIOCSFLAGS:
695 		error = suser(p->p_ucred, &p->p_acflag);
696 		if (error)
697 			break;
698 		sc->sc_swflags = *(int *)data;
699 		break;
700 
701 	case TIOCMSET:
702 	case TIOCMBIS:
703 	case TIOCMBIC:
704 		tiocm_to_ucom(sc, cmd, *(int *)data);
705 		break;
706 
707 	case TIOCMGET:
708 		*(int *)data = ucom_to_tiocm(sc);
709 		break;
710 
711 	default:
712 		error = ENOTTY;
713 		break;
714 	}
715 
716 	splx(s);
717 
718 	return (error);
719 }
720 
721 Static void
722 tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
723 {
724 	u_char combits;
725 
726 	combits = 0;
727 	if (ISSET(ttybits, TIOCM_DTR))
728 		SET(combits, UMCR_DTR);
729 	if (ISSET(ttybits, TIOCM_RTS))
730 		SET(combits, UMCR_RTS);
731 
732 	switch (how) {
733 	case TIOCMBIC:
734 		CLR(sc->sc_mcr, combits);
735 		break;
736 
737 	case TIOCMBIS:
738 		SET(sc->sc_mcr, combits);
739 		break;
740 
741 	case TIOCMSET:
742 		CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
743 		SET(sc->sc_mcr, combits);
744 		break;
745 	}
746 
747 	if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
748 		ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
749 	if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
750 		ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
751 }
752 
753 Static int
754 ucom_to_tiocm(struct ucom_softc *sc)
755 {
756 	u_char combits;
757 	int ttybits = 0;
758 
759 	combits = sc->sc_mcr;
760 	if (ISSET(combits, UMCR_DTR))
761 		SET(ttybits, TIOCM_DTR);
762 	if (ISSET(combits, UMCR_RTS))
763 		SET(ttybits, TIOCM_RTS);
764 
765 	combits = sc->sc_msr;
766 	if (ISSET(combits, UMSR_DCD))
767 		SET(ttybits, TIOCM_CD);
768 	if (ISSET(combits, UMSR_CTS))
769 		SET(ttybits, TIOCM_CTS);
770 	if (ISSET(combits, UMSR_DSR))
771 		SET(ttybits, TIOCM_DSR);
772 	if (ISSET(combits, UMSR_RI | UMSR_TERI))
773 		SET(ttybits, TIOCM_RI);
774 
775 #if 0
776 XXX;
777 	if (sc->sc_ier != 0)
778 		SET(ttybits, TIOCM_LE);
779 #endif
780 
781 	return (ttybits);
782 }
783 
784 Static void
785 ucom_break(sc, onoff)
786 	struct ucom_softc *sc;
787 	int onoff;
788 {
789 	DPRINTF(("ucom_break: onoff=%d\n", onoff));
790 
791 	if (sc->sc_methods->ucom_set != NULL)
792 		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
793 		    UCOM_SET_BREAK, onoff);
794 }
795 
796 Static void
797 ucom_dtr(struct ucom_softc *sc, int onoff)
798 {
799 	DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
800 
801 	if (sc->sc_methods->ucom_set != NULL)
802 		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
803 		    UCOM_SET_DTR, onoff);
804 }
805 
806 Static void
807 ucom_rts(struct ucom_softc *sc, int onoff)
808 {
809 	DPRINTF(("ucom_rts: onoff=%d\n", onoff));
810 
811 	if (sc->sc_methods->ucom_set != NULL)
812 		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
813 		    UCOM_SET_RTS, onoff);
814 }
815 
816 void
817 ucom_status_change(struct ucom_softc *sc)
818 {
819 	struct tty *tp = sc->sc_tty;
820 	u_char old_msr;
821 
822 	if (sc->sc_methods->ucom_get_status != NULL) {
823 		old_msr = sc->sc_msr;
824 		sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
825 		    &sc->sc_lsr, &sc->sc_msr);
826 		if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
827 			(*LINESW(tp, l_modem))(tp,
828 			    ISSET(sc->sc_msr, UMSR_DCD));
829 	} else {
830 		sc->sc_lsr = 0;
831 		sc->sc_msr = 0;
832 	}
833 }
834 
835 Static int
836 ucomparam(struct tty *tp, struct termios *t)
837 {
838 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
839 	int error;
840 
841 	if (sc->sc_dying)
842 		return (EIO);
843 
844 	/* Check requested parameters. */
845 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
846 		return (EINVAL);
847 
848 	/*
849 	 * For the console, always force CLOCAL and !HUPCL, so that the port
850 	 * is always active.
851 	 */
852 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
853 		SET(t->c_cflag, CLOCAL);
854 		CLR(t->c_cflag, HUPCL);
855 	}
856 
857 	/*
858 	 * If there were no changes, don't do anything.  This avoids dropping
859 	 * input and improves performance when all we did was frob things like
860 	 * VMIN and VTIME.
861 	 */
862 	if (tp->t_ospeed == t->c_ospeed &&
863 	    tp->t_cflag == t->c_cflag)
864 		return (0);
865 
866 	/* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
867 
868 	/* And copy to tty. */
869 	tp->t_ispeed = 0;
870 	tp->t_ospeed = t->c_ospeed;
871 	tp->t_cflag = t->c_cflag;
872 
873 	if (sc->sc_methods->ucom_param != NULL) {
874 		error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
875 			    t);
876 		if (error)
877 			return (error);
878 	}
879 
880 	/* XXX worry about CHWFLOW */
881 
882 	/*
883 	 * Update the tty layer's idea of the carrier bit, in case we changed
884 	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
885 	 * explicit request.
886 	 */
887 	DPRINTF(("ucomparam: l_modem\n"));
888 	(void) (*LINESW(tp, l_modem))(tp, 1 /* XXX carrier */ );
889 
890 #if 0
891 XXX what if the hardware is not open
892 	if (!ISSET(t->c_cflag, CHWFLOW)) {
893 		if (sc->sc_tx_stopped) {
894 			sc->sc_tx_stopped = 0;
895 			ucomstart(tp);
896 		}
897 	}
898 #endif
899 
900 	return (0);
901 }
902 
903 /*
904  * (un)block input via hw flowcontrol
905  */
906 Static void
907 ucom_hwiflow(struct ucom_softc *sc)
908 {
909 	DPRINTF(("ucom_hwiflow:\n"));
910 #if 0
911 XXX
912 	bus_space_tag_t iot = sc->sc_iot;
913 	bus_space_handle_t ioh = sc->sc_ioh;
914 
915 	if (sc->sc_mcr_rts == 0)
916 		return;
917 
918 	if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
919 		CLR(sc->sc_mcr, sc->sc_mcr_rts);
920 		CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
921 	} else {
922 		SET(sc->sc_mcr, sc->sc_mcr_rts);
923 		SET(sc->sc_mcr_active, sc->sc_mcr_rts);
924 	}
925 	bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
926 #endif
927 }
928 
929 Static void
930 ucomstart(struct tty *tp)
931 {
932 	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
933 	usbd_status err;
934 	int s;
935 	u_char *data;
936 	int cnt;
937 
938 	if (sc->sc_dying)
939 		return;
940 
941 	s = spltty();
942 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
943 		DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state));
944 		goto out;
945 	}
946 	if (sc->sc_tx_stopped)
947 		goto out;
948 
949 	if (tp->t_outq.c_cc <= tp->t_lowat) {
950 		if (ISSET(tp->t_state, TS_ASLEEP)) {
951 			CLR(tp->t_state, TS_ASLEEP);
952 			wakeup(&tp->t_outq);
953 		}
954 		selwakeup(&tp->t_wsel);
955 		if (tp->t_outq.c_cc == 0)
956 			goto out;
957 	}
958 
959 	/* Grab the first contiguous region of buffer space. */
960 	data = tp->t_outq.c_cf;
961 	cnt = ndqb(&tp->t_outq, 0);
962 
963 	if (cnt == 0) {
964 		DPRINTF(("ucomstart: cnt==0\n"));
965 		goto out;
966 	}
967 
968 	SET(tp->t_state, TS_BUSY);
969 
970 	if (cnt > sc->sc_obufsize) {
971 		DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
972 		cnt = sc->sc_obufsize;
973 	}
974 	if (sc->sc_methods->ucom_write != NULL)
975 		sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
976 					   sc->sc_obuf, data, &cnt);
977 	else
978 		memcpy(sc->sc_obuf, data, cnt);
979 
980 	DPRINTFN(4,("ucomstart: %d chars\n", cnt));
981 	usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
982 			(usbd_private_handle)sc, sc->sc_obuf, cnt,
983 			USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
984 	/* What can we do on error? */
985 	err = usbd_transfer(sc->sc_oxfer);
986 #ifdef DIAGNOSTIC
987 	if (err != USBD_IN_PROGRESS)
988 		printf("ucomstart: err=%s\n", usbd_errstr(err));
989 #endif
990 
991 out:
992 	splx(s);
993 }
994 
995 #if defined(__NetBSD__)
996 void
997 #else
998 int
999 #endif
1000 ucomstop(struct tty *tp, int flag)
1001 {
1002 	DPRINTF(("ucomstop: flag=%d\n", flag));
1003 #if 0
1004 	/*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
1005 	int s;
1006 
1007 	s = spltty();
1008 	if (ISSET(tp->t_state, TS_BUSY)) {
1009 		DPRINTF(("ucomstop: XXX\n"));
1010 		/* sc->sc_tx_stopped = 1; */
1011 		if (!ISSET(tp->t_state, TS_TTSTOP))
1012 			SET(tp->t_state, TS_FLUSH);
1013 	}
1014 	splx(s);
1015 #endif
1016 #if !defined(__NetBSD__)
1017 	return (0);
1018 #endif
1019 }
1020 
1021 Static void
1022 ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1023 {
1024 	struct ucom_softc *sc = (struct ucom_softc *)p;
1025 	struct tty *tp = sc->sc_tty;
1026 	u_int32_t cc;
1027 	int s;
1028 
1029 	DPRINTFN(5,("ucomwritecb: status=%d\n", status));
1030 
1031 	if (status == USBD_CANCELLED || sc->sc_dying)
1032 		goto error;
1033 
1034 	if (status) {
1035 		DPRINTF(("ucomwritecb: status=%d\n", status));
1036 		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1037 		/* XXX we should restart after some delay. */
1038 		goto error;
1039 	}
1040 
1041 	usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
1042 #if defined(__NetBSD__) && NRND > 0
1043 	rnd_add_uint32(&sc->sc_rndsource, cc);
1044 #endif
1045 	DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
1046 	/* convert from USB bytes to tty bytes */
1047 	cc -= sc->sc_opkthdrlen;
1048 
1049 	s = spltty();
1050 	CLR(tp->t_state, TS_BUSY);
1051 	if (ISSET(tp->t_state, TS_FLUSH))
1052 		CLR(tp->t_state, TS_FLUSH);
1053 	else
1054 		ndflush(&tp->t_outq, cc);
1055 	(*LINESW(tp, l_start))(tp);
1056 	splx(s);
1057 	return;
1058 
1059 error:
1060 	s = spltty();
1061 	CLR(tp->t_state, TS_BUSY);
1062 	splx(s);
1063 }
1064 
1065 Static usbd_status
1066 ucomstartread(struct ucom_softc *sc)
1067 {
1068 	usbd_status err;
1069 
1070 	DPRINTFN(5,("ucomstartread: start\n"));
1071 	usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
1072 			(usbd_private_handle)sc,
1073 			sc->sc_ibuf, sc->sc_ibufsize,
1074 			USBD_SHORT_XFER_OK | USBD_NO_COPY,
1075 			USBD_NO_TIMEOUT, ucomreadcb);
1076 	err = usbd_transfer(sc->sc_ixfer);
1077 	if (err != USBD_IN_PROGRESS) {
1078 		DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
1079 		return (err);
1080 	}
1081 	return (USBD_NORMAL_COMPLETION);
1082 }
1083 
1084 Static void
1085 ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1086 {
1087 	struct ucom_softc *sc = (struct ucom_softc *)p;
1088 	struct tty *tp = sc->sc_tty;
1089 	int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint);
1090 	usbd_status err;
1091 	u_int32_t cc;
1092 	u_char *cp;
1093 	int s;
1094 
1095 	DPRINTFN(5,("ucomreadcb: status=%d\n", status));
1096 
1097 	if (status == USBD_CANCELLED || status == USBD_IOERROR ||
1098 	    sc->sc_dying) {
1099 		DPRINTF(("ucomreadcb: dying\n"));
1100 		/* Send something to wake upper layer */
1101 		s = spltty();
1102 		(*rint)('\n', tp);
1103 		ttwakeup(tp);
1104 		splx(s);
1105 		return;
1106 	}
1107 
1108 	if (status) {
1109 		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1110 		/* XXX we should restart after some delay. */
1111 		return;
1112 	}
1113 
1114 	usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
1115 #if defined(__NetBSD__) && NRND > 0
1116 	rnd_add_uint32(&sc->sc_rndsource, cc);
1117 #endif
1118 	DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
1119 	if (sc->sc_methods->ucom_read != NULL)
1120 		sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
1121 					  &cp, &cc);
1122 
1123 	s = spltty();
1124 	/* Give characters to tty layer. */
1125 	while (cc-- > 0) {
1126 		DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
1127 		if ((*rint)(*cp++, tp) == -1) {
1128 			/* XXX what should we do? */
1129 			printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev),
1130 			       cc);
1131 			break;
1132 		}
1133 	}
1134 	splx(s);
1135 
1136 	err = ucomstartread(sc);
1137 	if (err) {
1138 		printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
1139 		/* XXX what should we dow now? */
1140 	}
1141 }
1142 
1143 Static void
1144 ucom_cleanup(struct ucom_softc *sc)
1145 {
1146 	DPRINTF(("ucom_cleanup: closing pipes\n"));
1147 
1148 	ucom_shutdown(sc);
1149 	if (sc->sc_bulkin_pipe != NULL) {
1150 		usbd_abort_pipe(sc->sc_bulkin_pipe);
1151 		usbd_close_pipe(sc->sc_bulkin_pipe);
1152 		sc->sc_bulkin_pipe = NULL;
1153 	}
1154 	if (sc->sc_bulkout_pipe != NULL) {
1155 		usbd_abort_pipe(sc->sc_bulkout_pipe);
1156 		usbd_close_pipe(sc->sc_bulkout_pipe);
1157 		sc->sc_bulkout_pipe = NULL;
1158 	}
1159 	if (sc->sc_ixfer != NULL) {
1160 		usbd_free_xfer(sc->sc_ixfer);
1161 		sc->sc_ixfer = NULL;
1162 	}
1163 	if (sc->sc_oxfer != NULL) {
1164 		usbd_free_xfer(sc->sc_oxfer);
1165 		sc->sc_oxfer = NULL;
1166 	}
1167 }
1168 
1169 #endif /* NUCOM > 0 */
1170 
1171 int
1172 ucomprint(void *aux, const char *pnp)
1173 {
1174 	struct ucom_attach_args *uca = aux;
1175 
1176 	if (pnp)
1177 		printf("ucom at %s", pnp);
1178 	if (uca->portno != UCOM_UNK_PORTNO)
1179 		printf(" portno %d", uca->portno);
1180 	return (UNCONF);
1181 }
1182 
1183 int
1184 #if defined(__OpenBSD__)
1185 ucomsubmatch(struct device *parent, void *match, void *aux)
1186 #else
1187 ucomsubmatch(struct device *parent, struct cfdata *cf, void *aux)
1188 #endif
1189 {
1190         struct ucom_attach_args *uca = aux;
1191 #if defined(__OpenBSD__)
1192         struct cfdata *cf = match;
1193 #endif
1194 
1195 	if (uca->portno != UCOM_UNK_PORTNO &&
1196 	    cf->ucomcf_portno != UCOM_UNK_PORTNO &&
1197 	    cf->ucomcf_portno != uca->portno)
1198 		return (0);
1199 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
1200 }
1201