Annotation of src/sys/dev/usb/ucom.c, Revision 1.105
1.105 ! dholland 1: /* $NetBSD: ucom.c,v 1.104 2014/05/04 22:18:38 christos Exp $ */
1.1 augustss 2:
3: /*
1.22 augustss 4: * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
1.1 augustss 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.23 augustss 8: * by Lennart Augustsson (lennart@augustsson.net) at
1.1 augustss 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: *
20: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
1.22 augustss 32: /*
33: * This code is very heavily based on the 16550 driver, com.c.
34: */
1.40 lukem 35:
36: #include <sys/cdefs.h>
1.105 ! dholland 37: __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.104 2014/05/04 22:18:38 christos Exp $");
1.1 augustss 38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/kernel.h>
42: #include <sys/ioctl.h>
1.3 augustss 43: #include <sys/conf.h>
1.1 augustss 44: #include <sys/tty.h>
45: #include <sys/file.h>
46: #include <sys/select.h>
47: #include <sys/proc.h>
48: #include <sys/vnode.h>
1.12 augustss 49: #include <sys/device.h>
1.1 augustss 50: #include <sys/poll.h>
1.82 martin 51: #include <sys/queue.h>
1.63 elad 52: #include <sys/kauth.h>
1.31 explorer 53: #include <sys/rnd.h>
1.1 augustss 54:
55: #include <dev/usb/usb.h>
56:
57: #include <dev/usb/usbdi.h>
58: #include <dev/usb/usbdi_util.h>
59: #include <dev/usb/usbdevs.h>
60: #include <dev/usb/usb_quirks.h>
61:
1.12 augustss 62: #include <dev/usb/ucomvar.h>
63:
1.13 augustss 64: #include "ucom.h"
65:
1.53 drochner 66: #include "locators.h"
67:
1.13 augustss 68: #if NUCOM > 0
69:
1.12 augustss 70: #ifdef UCOM_DEBUG
1.85 dyoung 71: #define DPRINTFN(n, x) if (ucomdebug > (n)) printf x
1.12 augustss 72: int ucomdebug = 0;
1.1 augustss 73: #else
1.12 augustss 74: #define DPRINTFN(n, x)
1.1 augustss 75: #endif
1.12 augustss 76: #define DPRINTF(x) DPRINTFN(0, x)
77:
78: #define UCOMUNIT_MASK 0x3ffff
79: #define UCOMDIALOUT_MASK 0x80000
80: #define UCOMCALLUNIT_MASK 0x40000
81:
82: #define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK)
83: #define UCOMDIALOUT(x) (minor(x) & UCOMDIALOUT_MASK)
84: #define UCOMCALLUNIT(x) (minor(x) & UCOMCALLUNIT_MASK)
85:
1.82 martin 86: /*
87: * XXX: We can submit multiple input/output buffers to the usb stack
88: * to improve throughput, but the usb stack is too lame to deal with this
89: * in a number of places.
90: */
91: #define UCOM_IN_BUFFS 1
92: #define UCOM_OUT_BUFFS 1
93:
94: struct ucom_buffer {
95: SIMPLEQ_ENTRY(ucom_buffer) ub_link;
96: usbd_xfer_handle ub_xfer;
97: u_char *ub_data;
98: u_int ub_len;
99: u_int ub_index;
100: };
101:
1.1 augustss 102: struct ucom_softc {
1.85 dyoung 103: device_t sc_dev; /* base device */
1.12 augustss 104:
105: usbd_device_handle sc_udev; /* USB device */
106:
107: usbd_interface_handle sc_iface; /* data interface */
108:
109: int sc_bulkin_no; /* bulk in endpoint address */
110: usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */
1.19 augustss 111: u_int sc_ibufsize; /* read buffer size */
1.22 augustss 112: u_int sc_ibufsizepad; /* read buffer size padded */
1.82 martin 113: struct ucom_buffer sc_ibuff[UCOM_IN_BUFFS];
114: SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_empty;
115: SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_full;
1.12 augustss 116:
117: int sc_bulkout_no; /* bulk out endpoint address */
118: usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */
1.19 augustss 119: u_int sc_obufsize; /* write buffer size */
1.82 martin 120: u_int sc_opkthdrlen; /* header length of */
121: struct ucom_buffer sc_obuff[UCOM_OUT_BUFFS];
122: SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_free;
123: SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_full;
124:
125: void *sc_si;
1.12 augustss 126:
1.90 jakllsch 127: const struct ucom_methods *sc_methods;
1.12 augustss 128: void *sc_parent;
129: int sc_portno;
130:
131: struct tty *sc_tty; /* our tty */
132: u_char sc_lsr;
133: u_char sc_msr;
134: u_char sc_mcr;
1.82 martin 135: volatile u_char sc_rx_stopped;
136: u_char sc_rx_unblock;
1.12 augustss 137: u_char sc_tx_stopped;
138: int sc_swflags;
139:
140: u_char sc_opening; /* lock during open */
1.17 augustss 141: int sc_refcnt;
1.12 augustss 142: u_char sc_dying; /* disconnecting */
1.31 explorer 143:
1.88 tls 144: krndsource_t sc_rndsource; /* random source */
1.1 augustss 145: };
146:
1.44 gehenna 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 = {
1.103 dholland 157: .d_open = ucomopen,
158: .d_close = ucomclose,
159: .d_read = ucomread,
160: .d_write = ucomwrite,
161: .d_ioctl = ucomioctl,
162: .d_stop = ucomstop,
163: .d_tty = ucomtty,
164: .d_poll = ucompoll,
165: .d_mmap = nommap,
166: .d_kqfilter = ttykqfilter,
1.105 ! dholland 167: .d_discard = nodiscard,
1.103 dholland 168: .d_flag = D_TTY
1.44 gehenna 169: };
1.12 augustss 170:
1.82 martin 171: static void ucom_cleanup(struct ucom_softc *);
172: static int ucomparam(struct tty *, struct termios *);
173: static int ucomhwiflow(struct tty *, int);
174: static void ucomstart(struct tty *);
175: static void ucom_shutdown(struct ucom_softc *);
176: static int ucom_do_ioctl(struct ucom_softc *, u_long, void *,
1.60 christos 177: int, struct lwp *);
1.82 martin 178: static void ucom_dtr(struct ucom_softc *, int);
179: static void ucom_rts(struct ucom_softc *, int);
180: static void ucom_break(struct ucom_softc *, int);
181: static void tiocm_to_ucom(struct ucom_softc *, u_long, int);
182: static int ucom_to_tiocm(struct ucom_softc *);
183:
184: static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
185: static void ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
186: static void ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
187: usbd_status);
188:
189: static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
190: static void ucom_read_complete(struct ucom_softc *);
191: static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
192: static void ucom_softintr(void *);
1.1 augustss 193:
1.85 dyoung 194: int ucom_match(device_t, cfdata_t, void *);
195: void ucom_attach(device_t, device_t, void *);
196: int ucom_detach(device_t, int);
197: int ucom_activate(device_t, enum devact);
198: extern struct cfdriver ucom_cd;
199: CFATTACH_DECL_NEW(ucom, sizeof(struct ucom_softc), ucom_match, ucom_attach,
200: ucom_detach, ucom_activate);
1.1 augustss 201:
1.85 dyoung 202: int
203: ucom_match(device_t parent, cfdata_t match, void *aux)
1.1 augustss 204: {
1.12 augustss 205: return (1);
1.1 augustss 206: }
207:
1.85 dyoung 208: void
209: ucom_attach(device_t parent, device_t self, void *aux)
1.1 augustss 210: {
1.77 cube 211: struct ucom_softc *sc = device_private(self);
1.12 augustss 212: struct ucom_attach_args *uca = aux;
213: struct tty *tp;
214:
1.35 augustss 215: if (uca->info != NULL)
1.83 pooka 216: aprint_normal(": %s", uca->info);
217: aprint_normal("\n");
1.12 augustss 218:
1.77 cube 219: sc->sc_dev = self;
1.12 augustss 220: sc->sc_udev = uca->device;
221: sc->sc_iface = uca->iface;
222: sc->sc_bulkout_no = uca->bulkout;
223: sc->sc_bulkin_no = uca->bulkin;
1.19 augustss 224: sc->sc_ibufsize = uca->ibufsize;
1.22 augustss 225: sc->sc_ibufsizepad = uca->ibufsizepad;
1.19 augustss 226: sc->sc_obufsize = uca->obufsize;
1.25 augustss 227: sc->sc_opkthdrlen = uca->opkthdrlen;
1.12 augustss 228: sc->sc_methods = uca->methods;
229: sc->sc_parent = uca->arg;
230: sc->sc_portno = uca->portno;
231:
1.82 martin 232: sc->sc_lsr = 0;
233: sc->sc_msr = 0;
234: sc->sc_mcr = 0;
235: sc->sc_tx_stopped = 0;
236: sc->sc_swflags = 0;
237: sc->sc_opening = 0;
238: sc->sc_refcnt = 0;
239: sc->sc_dying = 0;
240:
241: sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
242:
1.87 rmind 243: tp = tty_alloc();
1.12 augustss 244: tp->t_oproc = ucomstart;
245: tp->t_param = ucomparam;
1.82 martin 246: tp->t_hwiflow = ucomhwiflow;
1.12 augustss 247: sc->sc_tty = tp;
248:
249: DPRINTF(("ucom_attach: tty_attach %p\n", tp));
250: tty_attach(tp);
251:
1.85 dyoung 252: rnd_attach_source(&sc->sc_rndsource, device_xname(sc->sc_dev),
1.31 explorer 253: RND_TYPE_TTY, 0);
254:
1.74 smb 255: if (!pmf_device_register(self, NULL, NULL))
256: aprint_error_dev(self, "couldn't establish power handler\n");
1.85 dyoung 257: return;
1.12 augustss 258: }
259:
1.85 dyoung 260: int
261: ucom_detach(device_t self, int flags)
1.12 augustss 262: {
1.77 cube 263: struct ucom_softc *sc = device_private(self);
1.36 augustss 264: struct tty *tp = sc->sc_tty;
1.12 augustss 265: int maj, mn;
1.82 martin 266: int s, i;
1.12 augustss 267:
1.43 augustss 268: DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
1.36 augustss 269: sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
1.12 augustss 270:
271: sc->sc_dying = 1;
1.74 smb 272: pmf_device_deregister(self);
1.12 augustss 273:
1.33 augustss 274: if (sc->sc_bulkin_pipe != NULL)
275: usbd_abort_pipe(sc->sc_bulkin_pipe);
276: if (sc->sc_bulkout_pipe != NULL)
277: usbd_abort_pipe(sc->sc_bulkout_pipe);
1.12 augustss 278:
1.17 augustss 279: s = splusb();
280: if (--sc->sc_refcnt >= 0) {
1.35 augustss 281: /* Wake up anyone waiting */
1.36 augustss 282: if (tp != NULL) {
1.71 ad 283: mutex_spin_enter(&tty_lock);
1.36 augustss 284: CLR(tp->t_state, TS_CARR_ON);
285: CLR(tp->t_cflag, CLOCAL | MDMBUF);
286: ttyflush(tp, FREAD|FWRITE);
1.71 ad 287: mutex_spin_exit(&tty_lock);
1.36 augustss 288: }
1.17 augustss 289: /* Wait for processes to go away. */
1.99 mrg 290: usb_detach_waitold(sc->sc_dev);
1.17 augustss 291: }
1.82 martin 292:
293: softint_disestablish(sc->sc_si);
1.17 augustss 294: splx(s);
1.12 augustss 295:
296: /* locate the major number */
1.44 gehenna 297: maj = cdevsw_lookup_major(&ucom_cdevsw);
1.12 augustss 298:
299: /* Nuke the vnodes for any open instances. */
1.62 thorpej 300: mn = device_unit(self);
1.17 augustss 301: DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
1.12 augustss 302: vdevgone(maj, mn, mn, VCHR);
1.22 augustss 303: vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
304: vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
1.12 augustss 305:
306: /* Detach and free the tty. */
1.36 augustss 307: if (tp != NULL) {
308: tty_detach(tp);
1.87 rmind 309: tty_free(tp);
1.33 augustss 310: sc->sc_tty = NULL;
311: }
1.12 augustss 312:
1.82 martin 313: for (i = 0; i < UCOM_IN_BUFFS; i++) {
314: if (sc->sc_ibuff[i].ub_xfer != NULL)
315: usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
316: }
317:
318: for (i = 0; i < UCOM_OUT_BUFFS; i++) {
319: if (sc->sc_obuff[i].ub_xfer != NULL)
320: usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
321: }
322:
1.31 explorer 323: /* Detach the random source */
324: rnd_detach_source(&sc->sc_rndsource);
325:
1.12 augustss 326: return (0);
327: }
328:
329: int
1.85 dyoung 330: ucom_activate(device_t self, enum devact act)
1.12 augustss 331: {
1.77 cube 332: struct ucom_softc *sc = device_private(self);
1.12 augustss 333:
1.34 augustss 334: DPRINTFN(5,("ucom_activate: %d\n", act));
335:
1.12 augustss 336: switch (act) {
337: case DVACT_DEACTIVATE:
338: sc->sc_dying = 1;
1.81 dyoung 339: return 0;
340: default:
341: return EOPNOTSUPP;
1.12 augustss 342: }
343: }
344:
345: void
1.24 augustss 346: ucom_shutdown(struct ucom_softc *sc)
1.12 augustss 347: {
348: struct tty *tp = sc->sc_tty;
349:
350: DPRINTF(("ucom_shutdown\n"));
351: /*
352: * Hang up if necessary. Wait a bit, so the other side has time to
353: * notice even if we immediately open the port again.
354: */
355: if (ISSET(tp->t_cflag, HUPCL)) {
356: ucom_dtr(sc, 0);
357: (void)tsleep(sc, TTIPRI, ttclos, hz);
358: }
359: }
360:
361: int
1.69 christos 362: ucomopen(dev_t dev, int flag, int mode, struct lwp *l)
1.12 augustss 363: {
364: int unit = UCOMUNIT(dev);
365: usbd_status err;
1.77 cube 366: struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
1.82 martin 367: struct ucom_buffer *ub;
1.12 augustss 368: struct tty *tp;
1.82 martin 369: int s, i;
1.12 augustss 370: int error;
1.43 augustss 371:
1.12 augustss 372: if (sc == NULL)
373: return (ENXIO);
374:
375: if (sc->sc_dying)
376: return (EIO);
377:
1.77 cube 378: if (!device_is_active(sc->sc_dev))
1.12 augustss 379: return (ENXIO);
380:
381: tp = sc->sc_tty;
382:
383: DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
384:
1.66 elad 385: if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
1.12 augustss 386: return (EBUSY);
387:
388: s = spltty();
389:
390: /*
391: * Do the following iff this is a first open.
392: */
393: while (sc->sc_opening)
394: tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
1.17 augustss 395:
396: if (sc->sc_dying) {
397: splx(s);
398: return (EIO);
399: }
1.12 augustss 400: sc->sc_opening = 1;
1.43 augustss 401:
1.12 augustss 402: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
403: struct termios t;
404:
405: tp->t_dev = dev;
406:
1.22 augustss 407: if (sc->sc_methods->ucom_open != NULL) {
408: error = sc->sc_methods->ucom_open(sc->sc_parent,
409: sc->sc_portno);
410: if (error) {
411: ucom_cleanup(sc);
1.26 toshii 412: sc->sc_opening = 0;
413: wakeup(&sc->sc_opening);
414: splx(s);
1.22 augustss 415: return (error);
416: }
417: }
418:
1.12 augustss 419: ucom_status_change(sc);
420:
421: /*
422: * Initialize the termios status to the defaults. Add in the
423: * sticky bits from TIOCSFLAGS.
424: */
425: t.c_ispeed = 0;
426: t.c_ospeed = TTYDEF_SPEED;
427: t.c_cflag = TTYDEF_CFLAG;
428: if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
429: SET(t.c_cflag, CLOCAL);
430: if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
431: SET(t.c_cflag, CRTSCTS);
432: if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
433: SET(t.c_cflag, MDMBUF);
434: /* Make sure ucomparam() will do something. */
435: tp->t_ospeed = 0;
436: (void) ucomparam(tp, &t);
437: tp->t_iflag = TTYDEF_IFLAG;
438: tp->t_oflag = TTYDEF_OFLAG;
439: tp->t_lflag = TTYDEF_LFLAG;
440: ttychars(tp);
441: ttsetwater(tp);
442:
443: /*
444: * Turn on DTR. We must always do this, even if carrier is not
445: * present, because otherwise we'd have to use TIOCSDTR
446: * immediately after setting CLOCAL, which applications do not
447: * expect. We always assert DTR while the device is open
1.64 gson 448: * unless explicitly requested to deassert it. Ditto RTS.
1.12 augustss 449: */
450: ucom_dtr(sc, 1);
1.102 jakllsch 451: ucom_rts(sc, 1);
1.12 augustss 452:
453: DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
454: sc->sc_bulkin_no, sc->sc_bulkout_no));
455:
456: /* Open the bulk pipes */
1.82 martin 457: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
458: USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
1.12 augustss 459: if (err) {
1.52 nathanw 460: DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
1.85 dyoung 461: device_xname(sc->sc_dev), sc->sc_bulkin_no,
1.12 augustss 462: usbd_errstr(err)));
1.28 toshii 463: error = EIO;
1.26 toshii 464: goto fail_0;
1.12 augustss 465: }
466: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
467: USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
468: if (err) {
1.52 nathanw 469: DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
1.85 dyoung 470: device_xname(sc->sc_dev), sc->sc_bulkout_no,
1.12 augustss 471: usbd_errstr(err)));
1.28 toshii 472: error = EIO;
1.26 toshii 473: goto fail_1;
1.12 augustss 474: }
1.43 augustss 475:
1.82 martin 476: sc->sc_rx_unblock = 0;
477: sc->sc_rx_stopped = 0;
478: sc->sc_tx_stopped = 0;
479:
480: memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff));
481: memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff));
482:
483: SIMPLEQ_INIT(&sc->sc_ibuff_empty);
484: SIMPLEQ_INIT(&sc->sc_ibuff_full);
485: SIMPLEQ_INIT(&sc->sc_obuff_free);
486: SIMPLEQ_INIT(&sc->sc_obuff_full);
487:
488: /* Allocate input buffers */
489: for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
490: ub++) {
491: ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
492: if (ub->ub_xfer == NULL) {
493: error = ENOMEM;
494: goto fail_2;
495: }
496: ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
497: sc->sc_ibufsizepad);
498: if (ub->ub_data == NULL) {
499: error = ENOMEM;
500: goto fail_2;
501: }
1.26 toshii 502:
1.82 martin 503: if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) {
504: error = EIO;
505: goto fail_2;
506: }
1.28 toshii 507: }
1.12 augustss 508:
1.82 martin 509: for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
510: ub++) {
511: ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
512: if (ub->ub_xfer == NULL) {
513: error = ENOMEM;
514: goto fail_2;
515: }
516: ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
517: sc->sc_obufsize);
518: if (ub->ub_data == NULL) {
519: error = ENOMEM;
520: goto fail_2;
521: }
1.26 toshii 522:
1.82 martin 523: SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
1.28 toshii 524: }
1.12 augustss 525:
526: }
527: sc->sc_opening = 0;
528: wakeup(&sc->sc_opening);
529: splx(s);
530:
531: error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
532: if (error)
533: goto bad;
534:
1.32 eeh 535: error = (*tp->t_linesw->l_open)(dev, tp);
1.12 augustss 536: if (error)
537: goto bad;
538:
539: return (0);
1.26 toshii 540:
541: fail_2:
1.82 martin 542: usbd_abort_pipe(sc->sc_bulkin_pipe);
543: for (i = 0; i < UCOM_IN_BUFFS; i++) {
544: if (sc->sc_ibuff[i].ub_xfer != NULL) {
545: usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
546: sc->sc_ibuff[i].ub_xfer = NULL;
547: sc->sc_ibuff[i].ub_data = NULL;
548: }
549: }
550: usbd_abort_pipe(sc->sc_bulkout_pipe);
551: for (i = 0; i < UCOM_OUT_BUFFS; i++) {
552: if (sc->sc_obuff[i].ub_xfer != NULL) {
553: usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
554: sc->sc_obuff[i].ub_xfer = NULL;
555: sc->sc_obuff[i].ub_data = NULL;
556: }
557: }
558:
1.26 toshii 559: usbd_close_pipe(sc->sc_bulkout_pipe);
1.34 augustss 560: sc->sc_bulkout_pipe = NULL;
1.26 toshii 561: fail_1:
562: usbd_close_pipe(sc->sc_bulkin_pipe);
1.34 augustss 563: sc->sc_bulkin_pipe = NULL;
1.26 toshii 564: fail_0:
565: sc->sc_opening = 0;
566: wakeup(&sc->sc_opening);
567: splx(s);
1.28 toshii 568: return (error);
1.12 augustss 569:
570: bad:
1.82 martin 571: s = spltty();
572: CLR(tp->t_state, TS_BUSY);
1.12 augustss 573: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
574: /*
575: * We failed to open the device, and nobody else had it opened.
576: * Clean up the state as appropriate.
577: */
578: ucom_cleanup(sc);
579: }
1.82 martin 580: splx(s);
1.12 augustss 581:
582: return (error);
583: }
584:
585: int
1.69 christos 586: ucomclose(dev_t dev, int flag, int mode, struct lwp *l)
1.12 augustss 587: {
1.77 cube 588: struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101 jakllsch 589: struct tty *tp;
1.82 martin 590: int s;
1.12 augustss 591:
1.79 drochner 592: DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
1.101 jakllsch 593:
594: if (sc == NULL)
595: return 0;
596:
597: tp = sc->sc_tty;
598:
1.12 augustss 599: if (!ISSET(tp->t_state, TS_ISOPEN))
600: return (0);
601:
1.82 martin 602: s = spltty();
1.17 augustss 603: sc->sc_refcnt++;
604:
1.32 eeh 605: (*tp->t_linesw->l_close)(tp, flag);
1.12 augustss 606: ttyclose(tp);
607:
608: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
609: /*
610: * Although we got a last close, the device may still be in
611: * use; e.g. if this was the dialout node, and there are still
612: * processes waiting for carrier on the non-dialout node.
613: */
614: ucom_cleanup(sc);
615: }
616:
1.14 augustss 617: if (sc->sc_methods->ucom_close != NULL)
618: sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
619:
1.17 augustss 620: if (--sc->sc_refcnt < 0)
1.99 mrg 621: usb_detach_wakeupold(sc->sc_dev);
1.82 martin 622: splx(s);
1.17 augustss 623:
1.12 augustss 624: return (0);
625: }
1.43 augustss 626:
1.12 augustss 627: int
1.24 augustss 628: ucomread(dev_t dev, struct uio *uio, int flag)
1.12 augustss 629: {
1.77 cube 630: struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101 jakllsch 631: struct tty *tp;
1.17 augustss 632: int error;
1.12 augustss 633:
1.101 jakllsch 634: if (sc == NULL || sc->sc_dying)
1.12 augustss 635: return (EIO);
1.43 augustss 636:
1.101 jakllsch 637: tp = sc->sc_tty;
638:
1.17 augustss 639: sc->sc_refcnt++;
1.32 eeh 640: error = ((*tp->t_linesw->l_read)(tp, uio, flag));
1.17 augustss 641: if (--sc->sc_refcnt < 0)
1.99 mrg 642: usb_detach_wakeupold(sc->sc_dev);
1.17 augustss 643: return (error);
1.12 augustss 644: }
1.43 augustss 645:
1.12 augustss 646: int
1.24 augustss 647: ucomwrite(dev_t dev, struct uio *uio, int flag)
1.12 augustss 648: {
1.77 cube 649: struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101 jakllsch 650: struct tty *tp;
1.17 augustss 651: int error;
1.12 augustss 652:
1.101 jakllsch 653: if (sc == NULL || sc->sc_dying)
1.12 augustss 654: return (EIO);
1.43 augustss 655:
1.101 jakllsch 656: tp = sc->sc_tty;
657:
1.17 augustss 658: sc->sc_refcnt++;
1.32 eeh 659: error = ((*tp->t_linesw->l_write)(tp, uio, flag));
1.38 scw 660: if (--sc->sc_refcnt < 0)
1.99 mrg 661: usb_detach_wakeupold(sc->sc_dev);
1.38 scw 662: return (error);
663: }
664:
665: int
1.60 christos 666: ucompoll(dev_t dev, int events, struct lwp *l)
1.38 scw 667: {
1.94 jakllsch 668: struct ucom_softc *sc;
669: struct tty *tp;
1.56 ws 670: int revents;
1.38 scw 671:
1.94 jakllsch 672: sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
673: if (sc == NULL || sc->sc_dying)
1.56 ws 674: return (POLLHUP);
1.43 augustss 675:
1.94 jakllsch 676: tp = sc->sc_tty;
677:
1.38 scw 678: sc->sc_refcnt++;
1.60 christos 679: revents = ((*tp->t_linesw->l_poll)(tp, events, l));
1.17 augustss 680: if (--sc->sc_refcnt < 0)
1.99 mrg 681: usb_detach_wakeupold(sc->sc_dev);
1.56 ws 682: return (revents);
1.12 augustss 683: }
684:
685: struct tty *
1.24 augustss 686: ucomtty(dev_t dev)
1.12 augustss 687: {
1.77 cube 688: struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.12 augustss 689:
1.101 jakllsch 690: return ((sc != NULL) ? sc->sc_tty : NULL);
1.12 augustss 691: }
692:
693: int
1.70 christos 694: ucomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.12 augustss 695: {
1.77 cube 696: struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.17 augustss 697: int error;
698:
1.101 jakllsch 699: if (sc == NULL || sc->sc_dying)
700: return (EIO);
701:
1.17 augustss 702: sc->sc_refcnt++;
1.60 christos 703: error = ucom_do_ioctl(sc, cmd, data, flag, l);
1.17 augustss 704: if (--sc->sc_refcnt < 0)
1.99 mrg 705: usb_detach_wakeupold(sc->sc_dev);
1.17 augustss 706: return (error);
707: }
708:
1.82 martin 709: static int
1.70 christos 710: ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, void *data,
1.60 christos 711: int flag, struct lwp *l)
1.17 augustss 712: {
1.12 augustss 713: struct tty *tp = sc->sc_tty;
714: int error;
715: int s;
716:
717: DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
718:
1.60 christos 719: error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
1.42 atatat 720: if (error != EPASSTHROUGH)
1.12 augustss 721: return (error);
722:
1.60 christos 723: error = ttioctl(tp, cmd, data, flag, l);
1.42 atatat 724: if (error != EPASSTHROUGH)
1.12 augustss 725: return (error);
726:
727: if (sc->sc_methods->ucom_ioctl != NULL) {
728: error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
1.60 christos 729: sc->sc_portno, cmd, data, flag, l->l_proc);
1.42 atatat 730: if (error != EPASSTHROUGH)
1.12 augustss 731: return (error);
732: }
733:
734: error = 0;
735:
736: DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
737: s = spltty();
738:
739: switch (cmd) {
740: case TIOCSBRK:
741: ucom_break(sc, 1);
742: break;
743:
744: case TIOCCBRK:
745: ucom_break(sc, 0);
746: break;
747:
748: case TIOCSDTR:
749: ucom_dtr(sc, 1);
750: break;
751:
752: case TIOCCDTR:
753: ucom_dtr(sc, 0);
754: break;
755:
756: case TIOCGFLAGS:
757: *(int *)data = sc->sc_swflags;
758: break;
759:
760: case TIOCSFLAGS:
1.67 elad 761: error = kauth_authorize_device_tty(l->l_cred,
762: KAUTH_DEVICE_TTY_PRIVSET, tp);
1.12 augustss 763: if (error)
764: break;
765: sc->sc_swflags = *(int *)data;
766: break;
767:
768: case TIOCMSET:
769: case TIOCMBIS:
770: case TIOCMBIC:
771: tiocm_to_ucom(sc, cmd, *(int *)data);
772: break;
773:
774: case TIOCMGET:
775: *(int *)data = ucom_to_tiocm(sc);
776: break;
777:
778: default:
1.42 atatat 779: error = EPASSTHROUGH;
1.12 augustss 780: break;
781: }
782:
783: splx(s);
784:
785: return (error);
786: }
787:
1.82 martin 788: static void
1.29 toshii 789: tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
1.12 augustss 790: {
791: u_char combits;
1.3 augustss 792:
1.12 augustss 793: combits = 0;
794: if (ISSET(ttybits, TIOCM_DTR))
795: SET(combits, UMCR_DTR);
796: if (ISSET(ttybits, TIOCM_RTS))
797: SET(combits, UMCR_RTS);
1.43 augustss 798:
1.12 augustss 799: switch (how) {
800: case TIOCMBIC:
801: CLR(sc->sc_mcr, combits);
802: break;
803:
804: case TIOCMBIS:
805: SET(sc->sc_mcr, combits);
806: break;
807:
808: case TIOCMSET:
809: CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
810: SET(sc->sc_mcr, combits);
811: break;
812: }
813:
1.27 toshii 814: if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
815: ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
816: if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
817: ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
1.12 augustss 818: }
819:
1.82 martin 820: static int
1.24 augustss 821: ucom_to_tiocm(struct ucom_softc *sc)
1.12 augustss 822: {
823: u_char combits;
824: int ttybits = 0;
825:
826: combits = sc->sc_mcr;
827: if (ISSET(combits, UMCR_DTR))
828: SET(ttybits, TIOCM_DTR);
829: if (ISSET(combits, UMCR_RTS))
830: SET(ttybits, TIOCM_RTS);
831:
832: combits = sc->sc_msr;
833: if (ISSET(combits, UMSR_DCD))
834: SET(ttybits, TIOCM_CD);
835: if (ISSET(combits, UMSR_CTS))
836: SET(ttybits, TIOCM_CTS);
837: if (ISSET(combits, UMSR_DSR))
838: SET(ttybits, TIOCM_DSR);
839: if (ISSET(combits, UMSR_RI | UMSR_TERI))
840: SET(ttybits, TIOCM_RI);
841:
842: #if 0
843: XXX;
844: if (sc->sc_ier != 0)
845: SET(ttybits, TIOCM_LE);
846: #endif
847:
848: return (ttybits);
849: }
850:
1.82 martin 851: static void
1.77 cube 852: ucom_break(struct ucom_softc *sc, int onoff)
1.12 augustss 853: {
854: DPRINTF(("ucom_break: onoff=%d\n", onoff));
855:
1.14 augustss 856: if (sc->sc_methods->ucom_set != NULL)
857: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
858: UCOM_SET_BREAK, onoff);
1.12 augustss 859: }
860:
1.82 martin 861: static void
1.24 augustss 862: ucom_dtr(struct ucom_softc *sc, int onoff)
1.12 augustss 863: {
864: DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
865:
1.14 augustss 866: if (sc->sc_methods->ucom_set != NULL)
1.43 augustss 867: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1.14 augustss 868: UCOM_SET_DTR, onoff);
1.12 augustss 869: }
870:
1.82 martin 871: static void
1.24 augustss 872: ucom_rts(struct ucom_softc *sc, int onoff)
1.12 augustss 873: {
874: DPRINTF(("ucom_rts: onoff=%d\n", onoff));
875:
1.14 augustss 876: if (sc->sc_methods->ucom_set != NULL)
1.43 augustss 877: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1.14 augustss 878: UCOM_SET_RTS, onoff);
1.12 augustss 879: }
880:
1.22 augustss 881: void
1.24 augustss 882: ucom_status_change(struct ucom_softc *sc)
1.12 augustss 883: {
1.27 toshii 884: struct tty *tp = sc->sc_tty;
885: u_char old_msr;
886:
1.14 augustss 887: if (sc->sc_methods->ucom_get_status != NULL) {
1.27 toshii 888: old_msr = sc->sc_msr;
1.14 augustss 889: sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
890: &sc->sc_lsr, &sc->sc_msr);
1.27 toshii 891: if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
1.32 eeh 892: (*tp->t_linesw->l_modem)(tp,
1.27 toshii 893: ISSET(sc->sc_msr, UMSR_DCD));
1.14 augustss 894: } else {
895: sc->sc_lsr = 0;
1.54 augustss 896: /* Assume DCD is present, if we have no chance to check it. */
897: sc->sc_msr = UMSR_DCD;
1.14 augustss 898: }
1.12 augustss 899: }
900:
1.82 martin 901: static int
1.24 augustss 902: ucomparam(struct tty *tp, struct termios *t)
1.12 augustss 903: {
1.77 cube 904: struct ucom_softc *sc = device_lookup_private(&ucom_cd,
905: UCOMUNIT(tp->t_dev));
1.14 augustss 906: int error;
1.12 augustss 907:
1.101 jakllsch 908: if (sc == NULL || sc->sc_dying)
1.12 augustss 909: return (EIO);
910:
911: /* Check requested parameters. */
912: if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
913: return (EINVAL);
914:
915: /*
916: * For the console, always force CLOCAL and !HUPCL, so that the port
917: * is always active.
918: */
919: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
920: SET(t->c_cflag, CLOCAL);
921: CLR(t->c_cflag, HUPCL);
922: }
923:
924: /*
925: * If there were no changes, don't do anything. This avoids dropping
926: * input and improves performance when all we did was frob things like
927: * VMIN and VTIME.
928: */
929: if (tp->t_ospeed == t->c_ospeed &&
930: tp->t_cflag == t->c_cflag)
931: return (0);
932:
1.30 augustss 933: /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
1.12 augustss 934:
935: /* And copy to tty. */
936: tp->t_ispeed = 0;
937: tp->t_ospeed = t->c_ospeed;
938: tp->t_cflag = t->c_cflag;
939:
1.14 augustss 940: if (sc->sc_methods->ucom_param != NULL) {
941: error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
942: t);
943: if (error)
944: return (error);
945: }
1.12 augustss 946:
1.30 augustss 947: /* XXX worry about CHWFLOW */
1.12 augustss 948:
949: /*
950: * Update the tty layer's idea of the carrier bit, in case we changed
951: * CLOCAL or MDMBUF. We don't hang up here; we only do that by
952: * explicit request.
953: */
954: DPRINTF(("ucomparam: l_modem\n"));
1.54 augustss 955: (void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, UMSR_DCD));
1.12 augustss 956:
957: #if 0
958: XXX what if the hardware is not open
959: if (!ISSET(t->c_cflag, CHWFLOW)) {
960: if (sc->sc_tx_stopped) {
961: sc->sc_tx_stopped = 0;
962: ucomstart(tp);
963: }
964: }
965: #endif
966:
967: return (0);
968: }
969:
1.82 martin 970: static int
971: ucomhwiflow(struct tty *tp, int block)
1.12 augustss 972: {
1.82 martin 973: struct ucom_softc *sc = device_lookup_private(&ucom_cd,
974: UCOMUNIT(tp->t_dev));
975: int old;
1.12 augustss 976:
1.101 jakllsch 977: if (sc == NULL)
978: return (0);
979:
1.82 martin 980: old = sc->sc_rx_stopped;
981: sc->sc_rx_stopped = (u_char)block;
1.12 augustss 982:
1.82 martin 983: if (old && !block) {
984: int s = splusb();
985: sc->sc_rx_unblock = 1;
986: softint_schedule(sc->sc_si);
987: splx(s);
1.12 augustss 988: }
1.82 martin 989:
990: return (1);
1.1 augustss 991: }
1.3 augustss 992:
1.82 martin 993: static void
1.24 augustss 994: ucomstart(struct tty *tp)
1.12 augustss 995: {
1.77 cube 996: struct ucom_softc *sc = device_lookup_private(&ucom_cd,
997: UCOMUNIT(tp->t_dev));
1.82 martin 998: struct ucom_buffer *ub;
1.12 augustss 999: int s;
1000: u_char *data;
1001: int cnt;
1002:
1.101 jakllsch 1003: if (sc == NULL || sc->sc_dying)
1.12 augustss 1004: return;
1005:
1006: s = spltty();
1.84 christos 1007: if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1.12 augustss 1008: goto out;
1009: if (sc->sc_tx_stopped)
1010: goto out;
1011:
1.82 martin 1012: if (!ttypull(tp))
1.73 ad 1013: goto out;
1.12 augustss 1014:
1015: /* Grab the first contiguous region of buffer space. */
1016: data = tp->t_outq.c_cf;
1017: cnt = ndqb(&tp->t_outq, 0);
1018:
1.84 christos 1019: if (cnt == 0)
1.12 augustss 1020: goto out;
1021:
1.82 martin 1022: ub = SIMPLEQ_FIRST(&sc->sc_obuff_free);
1.100 mlelstv 1023: if (ub == NULL) {
1024: SET(tp->t_state, TS_BUSY);
1025: goto out;
1026: }
1.82 martin 1027: SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_free, ub_link);
1.12 augustss 1028:
1.82 martin 1029: if (SIMPLEQ_FIRST(&sc->sc_obuff_free) == NULL)
1030: SET(tp->t_state, TS_BUSY);
1031:
1032: if (cnt > sc->sc_obufsize)
1.19 augustss 1033: cnt = sc->sc_obufsize;
1.82 martin 1034:
1.22 augustss 1035: if (sc->sc_methods->ucom_write != NULL)
1036: sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
1.82 martin 1037: ub->ub_data, data, &cnt);
1.22 augustss 1038: else
1.82 martin 1039: memcpy(ub->ub_data, data, cnt);
1040:
1041: ub->ub_len = cnt;
1042: ub->ub_index = 0;
1.12 augustss 1043:
1.82 martin 1044: SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_full, ub, ub_link);
1045:
1046: softint_schedule(sc->sc_si);
1.3 augustss 1047:
1.82 martin 1048: out:
1.12 augustss 1049: splx(s);
1050: }
1051:
1.21 itojun 1052: void
1.69 christos 1053: ucomstop(struct tty *tp, int flag)
1.12 augustss 1054: {
1.19 augustss 1055: #if 0
1.77 cube 1056: /*struct ucom_softc *sc =
1.91 jakllsch 1057: device_lookup_private(&ucom_cd, UCOMUNIT(tp->t_dev));*/
1.12 augustss 1058: int s;
1059:
1060: s = spltty();
1061: if (ISSET(tp->t_state, TS_BUSY)) {
1.19 augustss 1062: /* sc->sc_tx_stopped = 1; */
1.12 augustss 1063: if (!ISSET(tp->t_state, TS_TTSTOP))
1064: SET(tp->t_state, TS_FLUSH);
1065: }
1066: splx(s);
1.19 augustss 1067: #endif
1.12 augustss 1068: }
1069:
1.82 martin 1070: static void
1071: ucom_write_status(struct ucom_softc *sc, struct ucom_buffer *ub,
1072: usbd_status err)
1073: {
1074: struct tty *tp = sc->sc_tty;
1075: uint32_t cc = ub->ub_len;
1076:
1077: switch (err) {
1078: case USBD_IN_PROGRESS:
1079: ub->ub_index = ub->ub_len;
1080: break;
1081: case USBD_STALLED:
1082: ub->ub_index = 0;
1083: softint_schedule(sc->sc_si);
1084: break;
1085: case USBD_NORMAL_COMPLETION:
1086: usbd_get_xfer_status(ub->ub_xfer, NULL, NULL, &cc, NULL);
1087: rnd_add_uint32(&sc->sc_rndsource, cc);
1088: /*FALLTHROUGH*/
1089: default:
1090: SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_full, ub_link);
1091: SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
1092: cc -= sc->sc_opkthdrlen;
1093:
1.100 mlelstv 1094: mutex_spin_enter(&tty_lock);
1.82 martin 1095: CLR(tp->t_state, TS_BUSY);
1096: if (ISSET(tp->t_state, TS_FLUSH))
1097: CLR(tp->t_state, TS_FLUSH);
1098: else
1099: ndflush(&tp->t_outq, cc);
1.100 mlelstv 1100: mutex_spin_exit(&tty_lock);
1.82 martin 1101:
1102: if (err != USBD_CANCELLED && err != USBD_IOERROR &&
1103: !sc->sc_dying) {
1104: if ((ub = SIMPLEQ_FIRST(&sc->sc_obuff_full)) != NULL)
1105: ucom_submit_write(sc, ub);
1106:
1107: (*tp->t_linesw->l_start)(tp);
1108: }
1109: break;
1110: }
1111: }
1112:
1113: /* Call at spltty() */
1114: static void
1115: ucom_submit_write(struct ucom_softc *sc, struct ucom_buffer *ub)
1116: {
1117:
1118: usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkout_pipe,
1119: (usbd_private_handle)sc, ub->ub_data, ub->ub_len,
1120: USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
1121:
1122: ucom_write_status(sc, ub, usbd_transfer(ub->ub_xfer));
1123: }
1124:
1125: static void
1.24 augustss 1126: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1.12 augustss 1127: {
1128: struct ucom_softc *sc = (struct ucom_softc *)p;
1.82 martin 1129: int s;
1130:
1131: s = spltty();
1132:
1133: ucom_write_status(sc, SIMPLEQ_FIRST(&sc->sc_obuff_full), status);
1134:
1135: splx(s);
1136: }
1137:
1138: static void
1139: ucom_softintr(void *arg)
1140: {
1141: struct ucom_softc *sc = arg;
1.12 augustss 1142: struct tty *tp = sc->sc_tty;
1.82 martin 1143: struct ucom_buffer *ub;
1.12 augustss 1144: int s;
1145:
1.82 martin 1146: if (!ISSET(tp->t_state, TS_ISOPEN))
1147: return;
1.12 augustss 1148:
1.82 martin 1149: s = spltty();
1.12 augustss 1150:
1.82 martin 1151: ub = SIMPLEQ_FIRST(&sc->sc_obuff_full);
1152:
1153: if (ub != NULL && ub->ub_index == 0)
1154: ucom_submit_write(sc, ub);
1.12 augustss 1155:
1.82 martin 1156: if (sc->sc_rx_unblock)
1157: ucom_read_complete(sc);
1.12 augustss 1158:
1.39 augustss 1159: splx(s);
1.82 martin 1160: }
1161:
1162: static void
1163: ucom_read_complete(struct ucom_softc *sc)
1164: {
1165: int (*rint)(int, struct tty *);
1166: struct ucom_buffer *ub;
1167: struct tty *tp;
1168: int s;
1169:
1170: tp = sc->sc_tty;
1171: rint = tp->t_linesw->l_rint;
1172: ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
1.39 augustss 1173:
1.82 martin 1174: while (ub != NULL && !sc->sc_rx_stopped) {
1175:
1176: s = spltty();
1177:
1178: while (ub->ub_index < ub->ub_len && !sc->sc_rx_stopped) {
1179: /* Give characters to tty layer. */
1180: if ((*rint)(ub->ub_data[ub->ub_index], tp) == -1) {
1181: /* Overflow: drop remainder */
1182: ub->ub_index = ub->ub_len;
1183: } else
1184: ub->ub_index++;
1185: }
1186:
1187: splx(s);
1188:
1189: if (ub->ub_index == ub->ub_len) {
1190: SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link);
1191:
1192: ucomsubmitread(sc, ub);
1193:
1194: ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
1195: }
1196: }
1197:
1198: sc->sc_rx_unblock = (ub != NULL);
1.12 augustss 1199: }
1200:
1.82 martin 1201: static usbd_status
1202: ucomsubmitread(struct ucom_softc *sc, struct ucom_buffer *ub)
1.12 augustss 1203: {
1204: usbd_status err;
1205:
1.82 martin 1206: usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkin_pipe,
1207: (usbd_private_handle)sc, ub->ub_data, sc->sc_ibufsize,
1208: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, ucomreadcb);
1209:
1210: if ((err = usbd_transfer(ub->ub_xfer)) != USBD_IN_PROGRESS) {
1211: /* XXX: Recover from this, please! */
1212: printf("ucomsubmitread: err=%s\n", usbd_errstr(err));
1.12 augustss 1213: return (err);
1214: }
1.82 martin 1215:
1216: SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_empty, ub, ub_link);
1217:
1.12 augustss 1218: return (USBD_NORMAL_COMPLETION);
1219: }
1.43 augustss 1220:
1.82 martin 1221: static void
1.24 augustss 1222: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1.12 augustss 1223: {
1224: struct ucom_softc *sc = (struct ucom_softc *)p;
1225: struct tty *tp = sc->sc_tty;
1.82 martin 1226: struct ucom_buffer *ub;
1.12 augustss 1227: u_int32_t cc;
1228: u_char *cp;
1229: int s;
1230:
1.82 martin 1231: ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
1232: SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
1.34 augustss 1233:
1234: if (status == USBD_CANCELLED || status == USBD_IOERROR ||
1235: sc->sc_dying) {
1236: DPRINTF(("ucomreadcb: dying\n"));
1.82 martin 1237: ub->ub_index = ub->ub_len = 0;
1.34 augustss 1238: /* Send something to wake upper layer */
1239: s = spltty();
1.82 martin 1240: if (status != USBD_CANCELLED) {
1241: (tp->t_linesw->l_rint)('\n', tp);
1242: mutex_spin_enter(&tty_lock); /* XXX */
1243: ttwakeup(tp);
1244: mutex_spin_exit(&tty_lock); /* XXX */
1245: }
1.34 augustss 1246: splx(s);
1.12 augustss 1247: return;
1.34 augustss 1248: }
1.12 augustss 1249:
1.82 martin 1250: if (status == USBD_STALLED) {
1.12 augustss 1251: usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1.82 martin 1252: ucomsubmitread(sc, ub);
1253: return;
1254: }
1255:
1256: if (status != USBD_NORMAL_COMPLETION) {
1257: printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
1.12 augustss 1258: return;
1259: }
1260:
1.48 thorpej 1261: usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
1.82 martin 1262:
1.95 jakllsch 1263: #ifdef UCOM_DEBUG
1264: /* This is triggered by uslsa(4) occasionally. */
1265: if ((ucomdebug > 0) && (cc == 0)) {
1266: device_printf(sc->sc_dev, "ucomreadcb: zero length xfer!\n");
1.82 martin 1267: }
1.95 jakllsch 1268: #endif
1.82 martin 1269:
1270: KDASSERT(cp == ub->ub_data);
1271:
1.31 explorer 1272: rnd_add_uint32(&sc->sc_rndsource, cc);
1.82 martin 1273:
1274: if (sc->sc_opening) {
1275: ucomsubmitread(sc, ub);
1276: return;
1277: }
1278:
1279: if (sc->sc_methods->ucom_read != NULL) {
1.22 augustss 1280: sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
1.82 martin 1281: &cp, &cc);
1282: ub->ub_index = (u_int)(cp - ub->ub_data);
1283: } else
1284: ub->ub_index = 0;
1285:
1286: ub->ub_len = cc;
1.22 augustss 1287:
1.82 martin 1288: SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link);
1.12 augustss 1289:
1.82 martin 1290: ucom_read_complete(sc);
1.12 augustss 1291: }
1292:
1.82 martin 1293: static void
1.24 augustss 1294: ucom_cleanup(struct ucom_softc *sc)
1.12 augustss 1295: {
1.82 martin 1296: struct ucom_buffer *ub;
1297:
1.12 augustss 1298: DPRINTF(("ucom_cleanup: closing pipes\n"));
1299:
1300: ucom_shutdown(sc);
1.33 augustss 1301: if (sc->sc_bulkin_pipe != NULL) {
1302: usbd_abort_pipe(sc->sc_bulkin_pipe);
1303: usbd_close_pipe(sc->sc_bulkin_pipe);
1304: sc->sc_bulkin_pipe = NULL;
1305: }
1306: if (sc->sc_bulkout_pipe != NULL) {
1307: usbd_abort_pipe(sc->sc_bulkout_pipe);
1308: usbd_close_pipe(sc->sc_bulkout_pipe);
1309: sc->sc_bulkout_pipe = NULL;
1310: }
1.82 martin 1311: for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) {
1312: if (ub->ub_xfer != NULL) {
1313: usbd_free_xfer(ub->ub_xfer);
1314: ub->ub_xfer = NULL;
1315: ub->ub_data = NULL;
1316: }
1317: }
1318: for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS]; ub++){
1319: if (ub->ub_xfer != NULL) {
1320: usbd_free_xfer(ub->ub_xfer);
1321: ub->ub_xfer = NULL;
1322: ub->ub_data = NULL;
1323: }
1.33 augustss 1324: }
1.12 augustss 1325: }
1.13 augustss 1326:
1327: #endif /* NUCOM > 0 */
1.12 augustss 1328:
1.20 augustss 1329: int
1.24 augustss 1330: ucomprint(void *aux, const char *pnp)
1.12 augustss 1331: {
1.37 augustss 1332: struct ucom_attach_args *uca = aux;
1.12 augustss 1333:
1334: if (pnp)
1.49 thorpej 1335: aprint_normal("ucom at %s", pnp);
1.37 augustss 1336: if (uca->portno != UCOM_UNK_PORTNO)
1.49 thorpej 1337: aprint_normal(" portno %d", uca->portno);
1.12 augustss 1338: return (UNCONF);
1339: }
1340:
1.20 augustss 1341: int
1.77 cube 1342: ucomsubmatch(device_t parent, cfdata_t cf,
1.69 christos 1343: const int *ldesc, void *aux)
1.12 augustss 1344: {
1345: struct ucom_attach_args *uca = aux;
1346:
1347: if (uca->portno != UCOM_UNK_PORTNO &&
1.53 drochner 1348: cf->cf_loc[UCOMBUSCF_PORTNO] != UCOMBUSCF_PORTNO_DEFAULT &&
1349: cf->cf_loc[UCOMBUSCF_PORTNO] != uca->portno)
1.12 augustss 1350: return (0);
1.46 thorpej 1351: return (config_match(parent, cf, aux));
1.12 augustss 1352: }
CVSweb <webmaster@jp.NetBSD.org>