Annotation of sys/dev/usb/ucom.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ucom.c,v 1.41 2007/06/14 10:11:15 mbalmer 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/rwlock.h>
48: #include <sys/ioctl.h>
49: #include <sys/conf.h>
50: #include <sys/tty.h>
51: #include <sys/file.h>
52: #include <sys/selinfo.h>
53: #include <sys/proc.h>
54: #include <sys/vnode.h>
55: #include <sys/device.h>
56: #include <sys/poll.h>
57:
58: #include <dev/usb/usb.h>
59:
60: #include <dev/usb/usbdi.h>
61: #include <dev/usb/usbdi_util.h>
62: #include <dev/usb/uhidev.h>
63: #include <dev/usb/usbdevs.h>
64: #include <dev/usb/usb_quirks.h>
65:
66: #include <dev/usb/ucomvar.h>
67:
68: #include "ucom.h"
69:
70: #if NUCOM > 0
71:
72: #ifdef UCOM_DEBUG
73: #define DPRINTFN(n, x) do { if (ucomdebug > (n)) printf x; } while (0)
74: int ucomdebug = 0;
75: #else
76: #define DPRINTFN(n, x)
77: #endif
78: #define DPRINTF(x) DPRINTFN(0, x)
79:
80: #define UCOMUNIT_MASK 0x7f
81: #define UCOMCUA_MASK 0x80
82:
83: #define LINESW(tp, func) (linesw[(tp)->t_line].func)
84:
85: #define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK)
86: #define UCOMCUA(x) (minor(x) & UCOMCUA_MASK)
87:
88: struct ucom_softc {
89: struct device sc_dev; /* base device */
90:
91: usbd_device_handle sc_udev; /* USB device */
92: struct uhidev_softc *sc_uhidev; /* hid device (if deeper) */
93:
94: usbd_interface_handle sc_iface; /* data interface */
95:
96: int sc_bulkin_no; /* bulk in endpoint address */
97: usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */
98: usbd_xfer_handle sc_ixfer; /* read request */
99: u_char *sc_ibuf; /* read buffer */
100: u_int sc_ibufsize; /* read buffer size */
101: u_int sc_ibufsizepad; /* read buffer size padded */
102:
103: int sc_bulkout_no; /* bulk out endpoint address */
104: usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */
105: usbd_xfer_handle sc_oxfer; /* write request */
106: u_char *sc_obuf; /* write buffer */
107: u_int sc_obufsize; /* write buffer size */
108: u_int sc_opkthdrlen; /* header length of
109: * output packet */
110:
111: usbd_pipe_handle sc_ipipe; /* hid interrupt input pipe */
112: usbd_pipe_handle sc_opipe; /* hid interrupt pipe */
113:
114: struct ucom_methods *sc_methods;
115: void *sc_parent;
116: int sc_portno;
117:
118: struct tty *sc_tty; /* our tty */
119: u_char sc_lsr;
120: u_char sc_msr;
121: u_char sc_mcr;
122: u_char sc_tx_stopped;
123: int sc_swflags;
124:
125: u_char sc_cua;
126:
127: struct rwlock sc_lock; /* lock during open */
128: int sc_open;
129: int sc_refcnt;
130: u_char sc_dying; /* disconnecting */
131: };
132:
133: void ucom_cleanup(struct ucom_softc *);
134: void ucom_hwiflow(struct ucom_softc *);
135: int ucomparam(struct tty *, struct termios *);
136: void ucomstart(struct tty *);
137: void ucom_shutdown(struct ucom_softc *);
138: int ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
139: int, struct proc *);
140: void ucom_dtr(struct ucom_softc *, int);
141: void ucom_rts(struct ucom_softc *, int);
142: void ucom_break(struct ucom_softc *, int);
143: usbd_status ucomstartread(struct ucom_softc *);
144: void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
145: void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
146: void tiocm_to_ucom(struct ucom_softc *, u_long, int);
147: int ucom_to_tiocm(struct ucom_softc *);
148: void ucom_lock(struct ucom_softc *);
149: void ucom_unlock(struct ucom_softc *);
150:
151: int ucom_match(struct device *, void *, void *);
152: void ucom_attach(struct device *, struct device *, void *);
153: int ucom_detach(struct device *, int);
154: int ucom_activate(struct device *, enum devact);
155:
156: struct cfdriver ucom_cd = {
157: NULL, "ucom", DV_DULL
158: };
159:
160: const struct cfattach ucom_ca = {
161: sizeof(struct ucom_softc),
162: ucom_match,
163: ucom_attach,
164: ucom_detach,
165: ucom_activate,
166: };
167:
168: void
169: ucom_lock(struct ucom_softc *sc)
170: {
171: sc->sc_refcnt++;
172: rw_enter_write(&sc->sc_lock);
173: }
174:
175: void
176: ucom_unlock(struct ucom_softc *sc)
177: {
178: rw_exit_write(&sc->sc_lock);
179: if (--sc->sc_refcnt < 0)
180: usb_detach_wakeup(&sc->sc_dev);
181: }
182:
183: int
184: ucom_match(struct device *parent, void *match, void *aux)
185: {
186: return (1);
187: }
188:
189: void
190: ucom_attach(struct device *parent, struct device *self, void *aux)
191: {
192: struct ucom_softc *sc = (struct ucom_softc *)self;
193: struct ucom_attach_args *uca = aux;
194: struct tty *tp;
195:
196: if (uca->info != NULL)
197: printf(", %s", uca->info);
198: printf("\n");
199:
200: sc->sc_udev = uca->device;
201: sc->sc_iface = uca->iface;
202: sc->sc_bulkout_no = uca->bulkout;
203: sc->sc_bulkin_no = uca->bulkin;
204: sc->sc_uhidev = uca->uhidev;
205: sc->sc_ibufsize = uca->ibufsize;
206: sc->sc_ibufsizepad = uca->ibufsizepad;
207: sc->sc_obufsize = uca->obufsize;
208: sc->sc_opkthdrlen = uca->opkthdrlen;
209: sc->sc_methods = uca->methods;
210: sc->sc_parent = uca->arg;
211: sc->sc_portno = uca->portno;
212:
213: tp = ttymalloc();
214: tp->t_oproc = ucomstart;
215: tp->t_param = ucomparam;
216: sc->sc_tty = tp;
217: sc->sc_cua = 0;
218:
219: rw_init(&sc->sc_lock, "ucomlk");
220:
221: sc->sc_open = 0;
222: }
223:
224: int
225: ucom_detach(struct device *self, int flags)
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(&sc->sc_dev);
252: }
253: splx(s);
254:
255: /* locate the major number */
256: for (maj = 0; maj < nchrdev; maj++)
257: if (cdevsw[maj].d_open == ucomopen)
258: break;
259:
260: /* Nuke the vnodes for any open instances. */
261: mn = self->dv_unit;
262: DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
263: vdevgone(maj, mn, mn, VCHR);
264: vdevgone(maj, mn | UCOMCUA_MASK, mn | UCOMCUA_MASK, VCHR);
265:
266: /* Detach and free the tty. */
267: if (tp != NULL) {
268: ttyfree(tp);
269: sc->sc_tty = NULL;
270: }
271:
272: return (0);
273: }
274:
275: int
276: ucom_activate(struct device *self, enum devact act)
277: {
278: struct ucom_softc *sc = (struct ucom_softc *)self;
279:
280: DPRINTFN(5,("ucom_activate: %d\n", act));
281:
282: switch (act) {
283: case DVACT_ACTIVATE:
284: break;
285:
286: case DVACT_DEACTIVATE:
287: sc->sc_dying = 1;
288: break;
289: }
290: return (0);
291: }
292:
293: void
294: ucom_shutdown(struct ucom_softc *sc)
295: {
296: struct tty *tp = sc->sc_tty;
297:
298: DPRINTF(("ucom_shutdown\n"));
299: /*
300: * Hang up if necessary. Wait a bit, so the other side has time to
301: * notice even if we immediately open the port again.
302: */
303: if (ISSET(tp->t_cflag, HUPCL)) {
304: ucom_dtr(sc, 0);
305: (void)tsleep(sc, TTIPRI, ttclos, hz);
306: }
307: }
308:
309: int
310: ucomopen(dev_t dev, int flag, int mode, struct proc *p)
311: {
312: int unit = UCOMUNIT(dev);
313: usbd_status err;
314: struct ucom_softc *sc;
315: struct tty *tp;
316: struct termios t;
317: int s;
318: int error;
319:
320: if (unit >= ucom_cd.cd_ndevs)
321: return (ENXIO);
322: sc = ucom_cd.cd_devs[unit];
323: if (sc == NULL)
324: return (ENXIO);
325:
326: if (sc->sc_dying)
327: return (EIO);
328:
329: if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
330: return (ENXIO);
331:
332: /* open the pipes if this is the first open */
333: ucom_lock(sc);
334: if (sc->sc_open++ == 0) {
335: s = splusb();
336:
337: DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
338: sc->sc_bulkin_no, sc->sc_bulkout_no));
339: DPRINTF(("ucomopen: hid %p pipes in=%p out=%p\n",
340: sc->sc_uhidev, sc->sc_ipipe, sc->sc_opipe));
341:
342: if (sc->sc_bulkin_no != -1) {
343:
344: /* Open the bulk pipes */
345: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
346: &sc->sc_bulkin_pipe);
347: if (err) {
348: DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
349: sc->sc_dev.dv_xname, sc->sc_bulkin_no,
350: usbd_errstr(err)));
351: error = EIO;
352: goto fail_0;
353: }
354: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
355: USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
356: if (err) {
357: DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
358: sc->sc_dev.dv_xname, sc->sc_bulkout_no,
359: usbd_errstr(err)));
360: error = EIO;
361: goto fail_1;
362: }
363:
364: /* Allocate a request and an input buffer and start reading. */
365: sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
366: if (sc->sc_ixfer == NULL) {
367: error = ENOMEM;
368: goto fail_2;
369: }
370:
371: sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
372: sc->sc_ibufsizepad);
373: if (sc->sc_ibuf == NULL) {
374: error = ENOMEM;
375: goto fail_2;
376: }
377:
378: sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
379: if (sc->sc_oxfer == NULL) {
380: error = ENOMEM;
381: goto fail_3;
382: }
383: } else {
384: /*
385: * input/output pipes and xfers already allocated
386: * as is the input buffer.
387: */
388: sc->sc_ipipe = sc->sc_uhidev->sc_ipipe;
389: sc->sc_ixfer = sc->sc_uhidev->sc_ixfer;
390: sc->sc_opipe = sc->sc_uhidev->sc_opipe;
391: sc->sc_oxfer = sc->sc_uhidev->sc_oxfer;
392: }
393:
394: sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
395: sc->sc_obufsize + sc->sc_opkthdrlen);
396: if (sc->sc_obuf == NULL) {
397: error = ENOMEM;
398: goto fail_4;
399: }
400:
401: if (sc->sc_methods->ucom_open != NULL) {
402: error = sc->sc_methods->ucom_open(sc->sc_parent,
403: sc->sc_portno);
404: if (error) {
405: ucom_cleanup(sc);
406: splx(s);
407: ucom_unlock(sc);
408: return (error);
409: }
410: }
411:
412: ucom_status_change(sc);
413:
414: ucomstartread(sc);
415:
416: splx(s);
417: }
418: ucom_unlock(sc);
419:
420: s = spltty();
421: tp = sc->sc_tty;
422: splx(s);
423:
424: DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
425:
426: tp->t_dev = dev;
427: if (!ISSET(tp->t_state, TS_ISOPEN)) {
428: SET(tp->t_state, TS_WOPEN);
429: ttychars(tp);
430:
431: /*
432: * Initialize the termios status to the defaults. Add in the
433: * sticky bits from TIOCSFLAGS.
434: */
435: t.c_ispeed = 0;
436: t.c_ospeed = TTYDEF_SPEED;
437: t.c_cflag = TTYDEF_CFLAG;
438: if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
439: SET(t.c_cflag, CLOCAL);
440: if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
441: SET(t.c_cflag, CRTSCTS);
442: if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
443: SET(t.c_cflag, MDMBUF);
444:
445: /* Make sure ucomparam() will do something. */
446: tp->t_ospeed = 0;
447: (void) ucomparam(tp, &t);
448: tp->t_iflag = TTYDEF_IFLAG;
449: tp->t_oflag = TTYDEF_OFLAG;
450: tp->t_lflag = TTYDEF_LFLAG;
451:
452: s = spltty();
453: ttsetwater(tp);
454:
455: /*
456: * Turn on DTR. We must always do this, even if carrier is not
457: * present, because otherwise we'd have to use TIOCSDTR
458: * immediately after setting CLOCAL, which applications do not
459: * expect. We always assert DTR while the device is open
460: * unless explicitly requested to deassert it.
461: */
462: ucom_dtr(sc, 1);
463:
464: /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
465: ucom_hwiflow(sc);
466:
467: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || UCOMCUA(dev) ||
468: ISSET(sc->sc_msr, UMSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
469: SET(tp->t_state, TS_CARR_ON);
470: else
471: CLR(tp->t_state, TS_CARR_ON);
472: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
473: error = EBUSY;
474: goto bad;
475: } else
476: s = spltty();
477:
478: if (UCOMCUA(dev)) {
479: if (ISSET(tp->t_state, TS_ISOPEN)) {
480: /* Someone is already dialed in */
481: error = EBUSY;
482: goto bad1;
483: }
484: sc->sc_cua = 1;
485: } else {
486: /* tty (not cua) device, wait for carrier */
487: if (ISSET(flag, O_NONBLOCK)) {
488: if (sc->sc_cua) {
489: error = EBUSY;
490: goto bad1;
491: }
492: } else {
493: while (sc->sc_cua || (!ISSET(tp->t_cflag, CLOCAL) &&
494: !ISSET(tp->t_state, TS_CARR_ON))) {
495: SET(tp->t_state, TS_WOPEN);
496: error = ttysleep(tp, &tp->t_rawq,
497: TTIPRI | PCATCH, ttopen, 0);
498: /*
499: * If TS_WOPEN has been reset, that means the
500: * cua device has been closed. We don't want
501: * to fail in that case, so just go around
502: * again.
503: */
504: if (error && ISSET(tp->t_state, TS_WOPEN)) {
505: CLR(tp->t_state, TS_WOPEN);
506: goto bad1;
507: }
508: }
509: }
510: }
511: splx(s);
512:
513: error = ttyopen(UCOMUNIT(dev), tp);
514: if (error)
515: goto bad;
516:
517: error = (*LINESW(tp, l_open))(dev, tp);
518: if (error)
519: goto bad;
520:
521: return (0);
522:
523: fail_4:
524: if (sc->sc_uhidev == NULL)
525: usbd_free_xfer(sc->sc_oxfer);
526: sc->sc_oxfer = NULL;
527: fail_3:
528: usbd_free_xfer(sc->sc_ixfer);
529: sc->sc_ixfer = NULL;
530: fail_2:
531: usbd_close_pipe(sc->sc_bulkout_pipe);
532: sc->sc_bulkout_pipe = NULL;
533: fail_1:
534: usbd_close_pipe(sc->sc_bulkin_pipe);
535: sc->sc_bulkin_pipe = NULL;
536: fail_0:
537: splx(s);
538: ucom_unlock(sc);
539: return (error);
540:
541: bad1:
542: splx(s);
543: bad:
544: ucom_lock(sc);
545: ucom_cleanup(sc);
546: ucom_unlock(sc);
547:
548: return (error);
549: }
550:
551: int
552: ucomclose(dev_t dev, int flag, int mode, struct proc *p)
553: {
554: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
555: struct tty *tp = sc->sc_tty;
556: int s;
557:
558: if (!ISSET(tp->t_state, TS_ISOPEN))
559: return (0);
560:
561: DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
562: ucom_lock(sc);
563:
564: (*LINESW(tp, l_close))(tp, flag);
565: s = spltty();
566: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
567: sc->sc_cua = 0;
568: ttyclose(tp);
569: ucom_cleanup(sc);
570: splx(s);
571:
572: if (sc->sc_methods->ucom_close != NULL)
573: sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
574:
575: ucom_unlock(sc);
576:
577: return (0);
578: }
579:
580: int
581: ucomread(dev_t dev, struct uio *uio, int flag)
582: {
583: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
584: struct tty *tp = sc->sc_tty;
585: int error;
586:
587: if (sc->sc_dying)
588: return (EIO);
589:
590: sc->sc_refcnt++;
591: error = (*LINESW(tp, l_read))(tp, uio, flag);
592: if (--sc->sc_refcnt < 0)
593: usb_detach_wakeup(&sc->sc_dev);
594: return (error);
595: }
596:
597: int
598: ucomwrite(dev_t dev, struct uio *uio, int flag)
599: {
600: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
601: struct tty *tp = sc->sc_tty;
602: int error;
603:
604: if (sc->sc_dying)
605: return (EIO);
606:
607: sc->sc_refcnt++;
608: error = (*LINESW(tp, l_write))(tp, uio, flag);
609: if (--sc->sc_refcnt < 0)
610: usb_detach_wakeup(&sc->sc_dev);
611: return (error);
612: }
613:
614: struct tty *
615: ucomtty(dev_t dev)
616: {
617: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
618: struct tty *tp = sc->sc_tty;
619:
620: return (tp);
621: }
622:
623: int
624: ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
625: {
626: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
627: int error;
628:
629: sc->sc_refcnt++;
630: error = ucom_do_ioctl(sc, cmd, data, flag, p);
631: if (--sc->sc_refcnt < 0)
632: usb_detach_wakeup(&sc->sc_dev);
633: return (error);
634: }
635:
636: int
637: ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
638: int flag, struct proc *p)
639: {
640: struct tty *tp = sc->sc_tty;
641: int error;
642: int s;
643:
644: if (sc->sc_dying)
645: return (EIO);
646:
647: DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
648:
649: error = (*LINESW(tp, l_ioctl))(tp, cmd, data, flag, p);
650: if (error >= 0)
651: return (error);
652:
653: error = ttioctl(tp, cmd, data, flag, p);
654: if (error >= 0)
655: return (error);
656:
657: if (sc->sc_methods->ucom_ioctl != NULL) {
658: error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
659: sc->sc_portno, cmd, data, flag, p);
660: if (error >= 0)
661: return (error);
662: }
663:
664: error = 0;
665:
666: DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
667: s = spltty();
668:
669: switch (cmd) {
670: case TIOCSBRK:
671: ucom_break(sc, 1);
672: break;
673:
674: case TIOCCBRK:
675: ucom_break(sc, 0);
676: break;
677:
678: case TIOCSDTR:
679: ucom_dtr(sc, 1);
680: break;
681:
682: case TIOCCDTR:
683: ucom_dtr(sc, 0);
684: break;
685:
686: case TIOCGFLAGS:
687: *(int *)data = sc->sc_swflags;
688: break;
689:
690: case TIOCSFLAGS:
691: error = suser(p, 0);
692: if (error)
693: break;
694: sc->sc_swflags = *(int *)data;
695: break;
696:
697: case TIOCMSET:
698: case TIOCMBIS:
699: case TIOCMBIC:
700: tiocm_to_ucom(sc, cmd, *(int *)data);
701: break;
702:
703: case TIOCMGET:
704: *(int *)data = ucom_to_tiocm(sc);
705: break;
706:
707: default:
708: error = ENOTTY;
709: break;
710: }
711:
712: splx(s);
713:
714: return (error);
715: }
716:
717: void
718: tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
719: {
720: u_char combits;
721:
722: combits = 0;
723: if (ISSET(ttybits, TIOCM_DTR))
724: SET(combits, UMCR_DTR);
725: if (ISSET(ttybits, TIOCM_RTS))
726: SET(combits, UMCR_RTS);
727:
728: switch (how) {
729: case TIOCMBIC:
730: CLR(sc->sc_mcr, combits);
731: break;
732:
733: case TIOCMBIS:
734: SET(sc->sc_mcr, combits);
735: break;
736:
737: case TIOCMSET:
738: CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
739: SET(sc->sc_mcr, combits);
740: break;
741: }
742:
743: if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
744: ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
745: if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
746: ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
747: }
748:
749: int
750: ucom_to_tiocm(struct ucom_softc *sc)
751: {
752: u_char combits;
753: int ttybits = 0;
754:
755: combits = sc->sc_mcr;
756: if (ISSET(combits, UMCR_DTR))
757: SET(ttybits, TIOCM_DTR);
758: if (ISSET(combits, UMCR_RTS))
759: SET(ttybits, TIOCM_RTS);
760:
761: combits = sc->sc_msr;
762: if (ISSET(combits, UMSR_DCD))
763: SET(ttybits, TIOCM_CD);
764: if (ISSET(combits, UMSR_CTS))
765: SET(ttybits, TIOCM_CTS);
766: if (ISSET(combits, UMSR_DSR))
767: SET(ttybits, TIOCM_DSR);
768: if (ISSET(combits, UMSR_RI | UMSR_TERI))
769: SET(ttybits, TIOCM_RI);
770:
771: #if 0
772: XXX;
773: if (sc->sc_ier != 0)
774: SET(ttybits, TIOCM_LE);
775: #endif
776:
777: return (ttybits);
778: }
779:
780: void
781: ucom_break(sc, onoff)
782: struct ucom_softc *sc;
783: int onoff;
784: {
785: DPRINTF(("ucom_break: onoff=%d\n", onoff));
786:
787: if (sc->sc_methods->ucom_set != NULL)
788: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
789: UCOM_SET_BREAK, onoff);
790: }
791:
792: void
793: ucom_dtr(struct ucom_softc *sc, int onoff)
794: {
795: DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
796:
797: if (sc->sc_methods->ucom_set != NULL) {
798: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
799: UCOM_SET_DTR, onoff);
800: /* When not using CRTSCTS, RTS follows DTR. */
801: if (!(sc->sc_swflags & TIOCFLAG_CRTSCTS))
802: ucom_rts(sc, onoff);
803: }
804: }
805:
806: 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:
827: ttytstamp(tp, old_msr & UMSR_CTS, sc->sc_msr & UMSR_CTS,
828: old_msr & UMSR_DCD, sc->sc_msr & UMSR_DCD);
829:
830: if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
831: (*LINESW(tp, l_modem))(tp,
832: ISSET(sc->sc_msr, UMSR_DCD));
833: } else {
834: sc->sc_lsr = 0;
835: sc->sc_msr = 0;
836: }
837: }
838:
839: int
840: ucomparam(struct tty *tp, struct termios *t)
841: {
842: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
843: int error;
844:
845: if (sc->sc_dying)
846: return (EIO);
847:
848: /* Check requested parameters. */
849: if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
850: return (EINVAL);
851:
852: /*
853: * For the console, always force CLOCAL and !HUPCL, so that the port
854: * is always active.
855: */
856: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
857: SET(t->c_cflag, CLOCAL);
858: CLR(t->c_cflag, HUPCL);
859: }
860:
861: /*
862: * If there were no changes, don't do anything. This avoids dropping
863: * input and improves performance when all we did was frob things like
864: * VMIN and VTIME.
865: */
866: if (tp->t_ospeed == t->c_ospeed &&
867: tp->t_cflag == t->c_cflag)
868: return (0);
869:
870: /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
871:
872: /* And copy to tty. */
873: tp->t_ispeed = 0;
874: tp->t_ospeed = t->c_ospeed;
875: tp->t_cflag = t->c_cflag;
876:
877: if (sc->sc_methods->ucom_param != NULL) {
878: error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
879: t);
880: if (error)
881: return (error);
882: }
883:
884: /* XXX worry about CHWFLOW */
885:
886: /*
887: * Update the tty layer's idea of the carrier bit, in case we changed
888: * CLOCAL or MDMBUF. We don't hang up here; we only do that by
889: * explicit request.
890: */
891: DPRINTF(("ucomparam: l_modem\n"));
892: (void) (*LINESW(tp, l_modem))(tp, 1 /* XXX carrier */ );
893:
894: #if 0
895: XXX what if the hardware is not open
896: if (!ISSET(t->c_cflag, CHWFLOW)) {
897: if (sc->sc_tx_stopped) {
898: sc->sc_tx_stopped = 0;
899: ucomstart(tp);
900: }
901: }
902: #endif
903:
904: return (0);
905: }
906:
907: /*
908: * (un)block input via hw flowcontrol
909: */
910: void
911: ucom_hwiflow(struct ucom_softc *sc)
912: {
913: DPRINTF(("ucom_hwiflow:\n"));
914: #if 0
915: XXX
916: bus_space_tag_t iot = sc->sc_iot;
917: bus_space_handle_t ioh = sc->sc_ioh;
918:
919: if (sc->sc_mcr_rts == 0)
920: return;
921:
922: if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
923: CLR(sc->sc_mcr, sc->sc_mcr_rts);
924: CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
925: } else {
926: SET(sc->sc_mcr, sc->sc_mcr_rts);
927: SET(sc->sc_mcr_active, sc->sc_mcr_rts);
928: }
929: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
930: #endif
931: }
932:
933: void
934: ucomstart(struct tty *tp)
935: {
936: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
937: usbd_status err;
938: int s;
939: u_char *data;
940: int cnt;
941:
942: if (sc->sc_dying)
943: return;
944:
945: s = spltty();
946: if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
947: DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state));
948: goto out;
949: }
950: if (sc->sc_tx_stopped)
951: goto out;
952:
953: if (tp->t_outq.c_cc <= tp->t_lowat) {
954: if (ISSET(tp->t_state, TS_ASLEEP)) {
955: CLR(tp->t_state, TS_ASLEEP);
956: wakeup(&tp->t_outq);
957: }
958: selwakeup(&tp->t_wsel);
959: if (tp->t_outq.c_cc == 0)
960: goto out;
961: }
962:
963: /* Grab the first contiguous region of buffer space. */
964: data = tp->t_outq.c_cf;
965: cnt = ndqb(&tp->t_outq, 0);
966:
967: if (cnt == 0) {
968: DPRINTF(("ucomstart: cnt==0\n"));
969: goto out;
970: }
971:
972: SET(tp->t_state, TS_BUSY);
973:
974: if (cnt > sc->sc_obufsize) {
975: DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
976: cnt = sc->sc_obufsize;
977: }
978: if (sc->sc_methods->ucom_write != NULL)
979: sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
980: sc->sc_obuf, data, &cnt);
981: else
982: memcpy(sc->sc_obuf, data, cnt);
983:
984: DPRINTFN(4,("ucomstart: %d chars\n", cnt));
985: #ifdef DIAGNOSTIC
986: if (sc->sc_oxfer == NULL) {
987: printf("ucomstart: null oxfer\n");
988: goto out;
989: }
990: #endif
991: if (sc->sc_bulkout_pipe != NULL) {
992: usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
993: (usbd_private_handle)sc, sc->sc_obuf, cnt,
994: USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
995: } else {
996: usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe,
997: (usbd_private_handle)sc, sc->sc_obuf, cnt,
998: USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
999: }
1000: /* What can we do on error? */
1001: err = usbd_transfer(sc->sc_oxfer);
1002: #ifdef DIAGNOSTIC
1003: if (err != USBD_IN_PROGRESS)
1004: printf("ucomstart: err=%s\n", usbd_errstr(err));
1005: #endif
1006:
1007: out:
1008: splx(s);
1009: }
1010:
1011: int
1012: ucomstop(struct tty *tp, int flag)
1013: {
1014: DPRINTF(("ucomstop: flag=%d\n", flag));
1015: #if 0
1016: /*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
1017: int s;
1018:
1019: s = spltty();
1020: if (ISSET(tp->t_state, TS_BUSY)) {
1021: DPRINTF(("ucomstop: XXX\n"));
1022: /* sc->sc_tx_stopped = 1; */
1023: if (!ISSET(tp->t_state, TS_TTSTOP))
1024: SET(tp->t_state, TS_FLUSH);
1025: }
1026: splx(s);
1027: #endif
1028: return (0);
1029: }
1030:
1031: void
1032: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1033: {
1034: struct ucom_softc *sc = (struct ucom_softc *)p;
1035: struct tty *tp = sc->sc_tty;
1036: u_int32_t cc;
1037: int s;
1038:
1039: DPRINTFN(5,("ucomwritecb: %p %p status=%d\n", xfer, p, status));
1040:
1041: if (status == USBD_CANCELLED || sc->sc_dying)
1042: goto error;
1043:
1044: if (sc->sc_bulkin_pipe != NULL) {
1045: if (status) {
1046: usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1047: /* XXX we should restart after some delay. */
1048: goto error;
1049: }
1050: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
1051: } else {
1052: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
1053: // XXX above gives me wrong cc, no?
1054: }
1055:
1056: DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
1057: /* convert from USB bytes to tty bytes */
1058: cc -= sc->sc_opkthdrlen;
1059:
1060: s = spltty();
1061: CLR(tp->t_state, TS_BUSY);
1062: if (ISSET(tp->t_state, TS_FLUSH))
1063: CLR(tp->t_state, TS_FLUSH);
1064: else
1065: ndflush(&tp->t_outq, cc);
1066: (*LINESW(tp, l_start))(tp);
1067: splx(s);
1068: return;
1069:
1070: error:
1071: s = spltty();
1072: CLR(tp->t_state, TS_BUSY);
1073: splx(s);
1074: }
1075:
1076: usbd_status
1077: ucomstartread(struct ucom_softc *sc)
1078: {
1079: usbd_status err;
1080:
1081: DPRINTFN(5,("ucomstartread: start\n"));
1082: #ifdef DIAGNOSTIC
1083: if (sc->sc_ixfer == NULL) {
1084: DPRINTF(("ucomstartread: null ixfer\n"));
1085: return (USBD_INVAL);
1086: }
1087: #endif
1088:
1089: if (sc->sc_bulkin_pipe != NULL) {
1090: usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
1091: (usbd_private_handle)sc,
1092: sc->sc_ibuf, sc->sc_ibufsize,
1093: USBD_SHORT_XFER_OK | USBD_NO_COPY,
1094: USBD_NO_TIMEOUT, ucomreadcb);
1095: err = usbd_transfer(sc->sc_ixfer);
1096: if (err != USBD_IN_PROGRESS) {
1097: DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
1098: return (err);
1099: }
1100: }
1101:
1102: return (USBD_NORMAL_COMPLETION);
1103: }
1104:
1105: void
1106: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1107: {
1108: struct ucom_softc *sc = (struct ucom_softc *)p;
1109: struct tty *tp = sc->sc_tty;
1110: int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint);
1111: usbd_status err;
1112: u_int32_t cc;
1113: u_char *cp;
1114: int s;
1115:
1116: DPRINTFN(5,("ucomreadcb: status=%d\n", status));
1117:
1118: if (status == USBD_CANCELLED || status == USBD_IOERROR ||
1119: sc->sc_dying) {
1120: DPRINTF(("ucomreadcb: dying\n"));
1121: /* Send something to wake upper layer */
1122: s = spltty();
1123: (*rint)('\n', tp);
1124: ttwakeup(tp);
1125: splx(s);
1126: return;
1127: }
1128:
1129: if (status) {
1130: if (sc->sc_bulkin_pipe != NULL) {
1131: usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1132: /* XXX we should restart after some delay. */
1133: return;
1134: }
1135: }
1136:
1137: usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
1138: DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
1139: if (sc->sc_methods->ucom_read != NULL)
1140: sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
1141: &cp, &cc);
1142:
1143: s = spltty();
1144: /* Give characters to tty layer. */
1145: while (cc-- > 0) {
1146: DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
1147: if ((*rint)(*cp++, tp) == -1) {
1148: /* XXX what should we do? */
1149: printf("%s: lost %d chars\n", sc->sc_dev.dv_xname,
1150: cc);
1151: break;
1152: }
1153: }
1154: splx(s);
1155:
1156: err = ucomstartread(sc);
1157: if (err) {
1158: printf("%s: read start failed\n", sc->sc_dev.dv_xname);
1159: /* XXX what should we dow now? */
1160: }
1161: }
1162:
1163: void
1164: ucom_cleanup(struct ucom_softc *sc)
1165: {
1166: if (--sc->sc_open == 0) {
1167: DPRINTF(("ucom_cleanup: closing pipes\n"));
1168:
1169: ucom_shutdown(sc);
1170: if (sc->sc_bulkin_pipe != NULL) {
1171: usbd_abort_pipe(sc->sc_bulkin_pipe);
1172: usbd_close_pipe(sc->sc_bulkin_pipe);
1173: sc->sc_bulkin_pipe = NULL;
1174: }
1175: if (sc->sc_bulkout_pipe != NULL) {
1176: usbd_abort_pipe(sc->sc_bulkout_pipe);
1177: usbd_close_pipe(sc->sc_bulkout_pipe);
1178: sc->sc_bulkout_pipe = NULL;
1179: }
1180: if (sc->sc_ixfer != NULL) {
1181: if (sc->sc_uhidev == NULL)
1182: usbd_free_xfer(sc->sc_ixfer);
1183: sc->sc_ixfer = NULL;
1184: }
1185: if (sc->sc_oxfer != NULL) {
1186: usbd_free_buffer(sc->sc_oxfer);
1187: if (sc->sc_uhidev == NULL)
1188: usbd_free_xfer(sc->sc_oxfer);
1189: sc->sc_oxfer = NULL;
1190: }
1191: }
1192: }
1193:
1194: #endif /* NUCOM > 0 */
1195:
1196: int
1197: ucomprint(void *aux, const char *pnp)
1198: {
1199: struct ucom_attach_args *uca = aux;
1200:
1201: if (pnp)
1202: printf("ucom at %s", pnp);
1203: if (uca->portno != UCOM_UNK_PORTNO)
1204: printf(" portno %d", uca->portno);
1205: return (UNCONF);
1206: }
1207:
1208: int
1209: ucomsubmatch(struct device *parent, void *match, void *aux)
1210: {
1211: struct ucom_attach_args *uca = aux;
1212: struct cfdata *cf = match;
1213:
1214: if (uca->portno != UCOM_UNK_PORTNO &&
1215: cf->ucomcf_portno != UCOM_UNK_PORTNO &&
1216: cf->ucomcf_portno != uca->portno)
1217: return (0);
1218: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
1219: }
CVSweb