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