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