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