1 /* $NetBSD: ucom.c,v 1.113 2016/05/14 10:52:29 mlelstv Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
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 */
32 /*
33 * This code is very heavily based on the 16550 driver, com.c.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.113 2016/05/14 10:52:29 mlelstv Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/ioctl.h>
43 #include <sys/conf.h>
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>
49 #include <sys/device.h>
50 #include <sys/poll.h>
51 #include <sys/queue.h>
52 #include <sys/kauth.h>
53 #include <sys/sysctl.h>
54 #include <sys/timepps.h>
55 #include <sys/rndsource.h>
56
57 #include <dev/usb/usb.h>
58
59 #include <dev/usb/usbdi.h>
60 #include <dev/usb/usbdi_util.h>
61 #include <dev/usb/usbdevs.h>
62 #include <dev/usb/usb_quirks.h>
63 #include <dev/usb/usbhist.h>
64
65 #include <dev/usb/ucomvar.h>
66
67 #include "ucom.h"
68
69 #include "locators.h"
70
71 #if NUCOM > 0
72
73 #ifdef USB_DEBUG
74 #ifndef UCOM_DEBUG
75 #define ucomdebug 0
76 #else
77 int ucomdebug = 0;
78
79 SYSCTL_SETUP(sysctl_hw_ucom_setup, "sysctl hw.ucom setup")
80 {
81 int err;
82 const struct sysctlnode *rnode;
83 const struct sysctlnode *cnode;
84
85 err = sysctl_createv(clog, 0, NULL, &rnode,
86 CTLFLAG_PERMANENT, CTLTYPE_NODE, "ucom",
87 SYSCTL_DESCR("ucom global controls"),
88 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
89
90 if (err)
91 goto fail;
92
93 /* control debugging printfs */
94 err = sysctl_createv(clog, 0, &rnode, &cnode,
95 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
96 "debug", SYSCTL_DESCR("Enable debugging output"),
97 NULL, 0, &ucomdebug, sizeof(ucomdebug), CTL_CREATE, CTL_EOL);
98 if (err)
99 goto fail;
100
101 return;
102 fail:
103 aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
104 }
105
106 #endif /* UCOM_DEBUG */
107 #endif /* USB_DEBUG */
108
109 #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(ucomdebug,1,FMT,A,B,C,D)
110 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ucomdebug,N,FMT,A,B,C,D)
111 #define UCOMHIST_FUNC() USBHIST_FUNC()
112 #define UCOMHIST_CALLED(name) USBHIST_CALLED(ucomdebug)
113
114 #define UCOMCALLUNIT_MASK TTCALLUNIT_MASK
115 #define UCOMUNIT_MASK TTUNIT_MASK
116 #define UCOMDIALOUT_MASK TTDIALOUT_MASK
117
118 #define UCOMCALLUNIT(x) TTCALLUNIT(x)
119 #define UCOMUNIT(x) TTUNIT(x)
120 #define UCOMDIALOUT(x) TTDIALOUT(x)
121
122 /*
123 * XXX: We can submit multiple input/output buffers to the usb stack
124 * to improve throughput, but the usb stack is too lame to deal with this
125 * in a number of places.
126 */
127 #define UCOM_IN_BUFFS 1
128 #define UCOM_OUT_BUFFS 1
129
130 struct ucom_buffer {
131 SIMPLEQ_ENTRY(ucom_buffer) ub_link;
132 struct usbd_xfer *ub_xfer;
133 u_char *ub_data;
134 u_int ub_len;
135 u_int ub_index;
136 };
137
138 struct ucom_softc {
139 device_t sc_dev; /* base device */
140
141 struct usbd_device * sc_udev; /* USB device */
142
143 struct usbd_interface * sc_iface; /* data interface */
144
145 int sc_bulkin_no; /* bulk in endpoint address */
146 struct usbd_pipe * sc_bulkin_pipe; /* bulk in pipe */
147 u_int sc_ibufsize; /* read buffer size */
148 u_int sc_ibufsizepad; /* read buffer size padded */
149 struct ucom_buffer sc_ibuff[UCOM_IN_BUFFS];
150 SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_empty;
151 SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_full;
152
153 int sc_bulkout_no; /* bulk out endpoint address */
154 struct usbd_pipe * sc_bulkout_pipe;/* bulk out pipe */
155 u_int sc_obufsize; /* write buffer size */
156 u_int sc_opkthdrlen; /* header length of */
157 struct ucom_buffer sc_obuff[UCOM_OUT_BUFFS];
158 SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_free;
159 SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_full;
160
161 void *sc_si;
162
163 const struct ucom_methods *sc_methods;
164 void *sc_parent;
165 int sc_portno;
166
167 struct tty *sc_tty; /* our tty */
168 u_char sc_lsr;
169 u_char sc_msr;
170 u_char sc_mcr;
171 volatile u_char sc_rx_stopped;
172 u_char sc_rx_unblock;
173 u_char sc_tx_stopped;
174 int sc_swflags;
175
176 u_char sc_opening; /* lock during open */
177 u_char sc_closing; /* lock during close */
178 int sc_refcnt;
179 u_char sc_dying; /* disconnecting */
180
181 struct pps_state sc_pps_state; /* pps state */
182
183 krndsource_t sc_rndsource; /* random source */
184
185 kmutex_t sc_lock;
186 kcondvar_t sc_opencv;
187 kcondvar_t sc_detachcv;
188 };
189
190 dev_type_open(ucomopen);
191 dev_type_close(ucomclose);
192 dev_type_read(ucomread);
193 dev_type_write(ucomwrite);
194 dev_type_ioctl(ucomioctl);
195 dev_type_stop(ucomstop);
196 dev_type_tty(ucomtty);
197 dev_type_poll(ucompoll);
198
199 const struct cdevsw ucom_cdevsw = {
200 .d_open = ucomopen,
201 .d_close = ucomclose,
202 .d_read = ucomread,
203 .d_write = ucomwrite,
204 .d_ioctl = ucomioctl,
205 .d_stop = ucomstop,
206 .d_tty = ucomtty,
207 .d_poll = ucompoll,
208 .d_mmap = nommap,
209 .d_kqfilter = ttykqfilter,
210 .d_discard = nodiscard,
211 .d_flag = D_TTY | D_MPSAFE
212 };
213
214 static void ucom_cleanup(struct ucom_softc *);
215 static int ucomparam(struct tty *, struct termios *);
216 static int ucomhwiflow(struct tty *, int);
217 static void ucomstart(struct tty *);
218 static void ucom_shutdown(struct ucom_softc *);
219 static int ucom_do_ioctl(struct ucom_softc *, u_long, void *,
220 int, struct lwp *);
221 static void ucom_dtr(struct ucom_softc *, int);
222 static void ucom_rts(struct ucom_softc *, int);
223 static void ucom_break(struct ucom_softc *, int);
224 static void tiocm_to_ucom(struct ucom_softc *, u_long, int);
225 static int ucom_to_tiocm(struct ucom_softc *);
226
227 static void ucomreadcb(struct usbd_xfer *, void *, usbd_status);
228 static void ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
229 static void ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
230 usbd_status);
231
232 static void ucomwritecb(struct usbd_xfer *, void *, usbd_status);
233 static void ucom_read_complete(struct ucom_softc *);
234 static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
235 static void ucom_softintr(void *);
236
237 int ucom_match(device_t, cfdata_t, void *);
238 void ucom_attach(device_t, device_t, void *);
239 int ucom_detach(device_t, int);
240 int ucom_activate(device_t, enum devact);
241 extern struct cfdriver ucom_cd;
242 CFATTACH_DECL_NEW(ucom, sizeof(struct ucom_softc), ucom_match, ucom_attach,
243 ucom_detach, ucom_activate);
244
245 int
ucom_match(device_t parent,cfdata_t match,void * aux)246 ucom_match(device_t parent, cfdata_t match, void *aux)
247 {
248 return 1;
249 }
250
251 void
ucom_attach(device_t parent,device_t self,void * aux)252 ucom_attach(device_t parent, device_t self, void *aux)
253 {
254 struct ucom_softc *sc = device_private(self);
255 struct ucom_attach_args *ucaa = aux;
256 struct tty *tp;
257
258 UCOMHIST_FUNC(); UCOMHIST_CALLED();
259
260 if (ucaa->ucaa_info != NULL)
261 aprint_normal(": %s", ucaa->ucaa_info);
262 aprint_normal("\n");
263
264 prop_dictionary_set_int32(device_properties(self), "port",
265 ucaa->ucaa_portno);
266
267 sc->sc_dev = self;
268 sc->sc_udev = ucaa->ucaa_device;
269 sc->sc_iface = ucaa->ucaa_iface;
270 sc->sc_bulkout_no = ucaa->ucaa_bulkout;
271 sc->sc_bulkin_no = ucaa->ucaa_bulkin;
272 sc->sc_ibufsize = ucaa->ucaa_ibufsize;
273 sc->sc_ibufsizepad = ucaa->ucaa_ibufsizepad;
274 sc->sc_obufsize = ucaa->ucaa_obufsize;
275 sc->sc_opkthdrlen = ucaa->ucaa_opkthdrlen;
276 sc->sc_methods = ucaa->ucaa_methods;
277 sc->sc_parent = ucaa->ucaa_arg;
278 sc->sc_portno = ucaa->ucaa_portno;
279
280 sc->sc_lsr = 0;
281 sc->sc_msr = 0;
282 sc->sc_mcr = 0;
283 sc->sc_tx_stopped = 0;
284 sc->sc_swflags = 0;
285 sc->sc_opening = 0;
286 sc->sc_closing = 0;
287 sc->sc_refcnt = 0;
288 sc->sc_dying = 0;
289
290 sc->sc_si = softint_establish(SOFTINT_USB, ucom_softintr, sc);
291 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
292 cv_init(&sc->sc_opencv, "ucomopen");
293 cv_init(&sc->sc_detachcv, "ucomdtch");
294
295 SIMPLEQ_INIT(&sc->sc_ibuff_empty);
296 SIMPLEQ_INIT(&sc->sc_ibuff_full);
297 SIMPLEQ_INIT(&sc->sc_obuff_free);
298 SIMPLEQ_INIT(&sc->sc_obuff_full);
299
300 memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff));
301 memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff));
302
303 DPRINTF("open pipes in=%d out=%d", sc->sc_bulkin_no, sc->sc_bulkout_no,
304 0, 0);
305
306 struct ucom_buffer *ub;
307 usbd_status err;
308 int error;
309
310 /* Open the bulk pipes */
311 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
312 USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
313 if (err) {
314 DPRINTF("open bulk in error (addr %d), err=%d",
315 sc->sc_bulkin_no, err, 0, 0);
316 error = EIO;
317 goto fail_0;
318 }
319 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
320 USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
321 if (err) {
322 DPRINTF("open bulk out error (addr %d), err=%d",
323 sc->sc_bulkout_no, err, 0, 0);
324 error = EIO;
325 goto fail_1;
326 }
327
328 /* Allocate input buffers */
329 for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
330 ub++) {
331 error = usbd_create_xfer(sc->sc_bulkin_pipe, sc->sc_ibufsizepad,
332 USBD_SHORT_XFER_OK, 0, &ub->ub_xfer);
333 if (error)
334 goto fail_2;
335 ub->ub_data = usbd_get_buffer(ub->ub_xfer);
336 }
337
338 for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
339 ub++) {
340 error = usbd_create_xfer(sc->sc_bulkout_pipe, sc->sc_obufsize,
341 0, 0, &ub->ub_xfer);
342 if (error)
343 goto fail_2;
344 ub->ub_data = usbd_get_buffer(ub->ub_xfer);
345 SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
346 }
347
348 tp = tty_alloc();
349 tp->t_oproc = ucomstart;
350 tp->t_param = ucomparam;
351 tp->t_hwiflow = ucomhwiflow;
352 sc->sc_tty = tp;
353
354 DPRINTF("tty_attach %p", tp, 0, 0, 0);
355 tty_attach(tp);
356
357 rnd_attach_source(&sc->sc_rndsource, device_xname(sc->sc_dev),
358 RND_TYPE_TTY, RND_FLAG_DEFAULT);
359
360 if (!pmf_device_register(self, NULL, NULL))
361 aprint_error_dev(self, "couldn't establish power handler\n");
362 return;
363
364 fail_2:
365 for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
366 ub++) {
367 if (ub->ub_xfer)
368 usbd_destroy_xfer(ub->ub_xfer);
369 }
370 for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
371 ub++) {
372 if (ub->ub_xfer)
373 usbd_destroy_xfer(ub->ub_xfer);
374 }
375
376 fail_1:
377 usbd_close_pipe(sc->sc_bulkin_pipe);
378
379 fail_0:
380 aprint_error_dev(self, "attach failed, error=%d\n", error);
381
382 return;
383 }
384
385 int
ucom_detach(device_t self,int flags)386 ucom_detach(device_t self, int flags)
387 {
388 struct ucom_softc *sc = device_private(self);
389 struct tty *tp = sc->sc_tty;
390 int maj, mn;
391 int i;
392
393 UCOMHIST_FUNC(); UCOMHIST_CALLED();
394
395 DPRINTF("sc=%p flags=%d tp=%p", sc, flags, tp, 0);
396 DPRINTF("... pipe=%d,%d",sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
397
398 mutex_enter(&sc->sc_lock);
399 sc->sc_dying = 1;
400 mutex_exit(&sc->sc_lock);
401
402 pmf_device_deregister(self);
403
404 if (sc->sc_bulkin_pipe != NULL)
405 usbd_abort_pipe(sc->sc_bulkin_pipe);
406 if (sc->sc_bulkout_pipe != NULL)
407 usbd_abort_pipe(sc->sc_bulkout_pipe);
408
409 mutex_enter(&sc->sc_lock);
410 while (sc->sc_refcnt > 0) {
411 /* Wake up anyone waiting */
412 if (tp != NULL) {
413 mutex_spin_enter(&tty_lock);
414 CLR(tp->t_state, TS_CARR_ON);
415 CLR(tp->t_cflag, CLOCAL | MDMBUF);
416 ttyflush(tp, FREAD|FWRITE);
417 mutex_spin_exit(&tty_lock);
418 }
419 /* Wait for processes to go away. */
420 usb_detach_wait(sc->sc_dev, &sc->sc_detachcv, &sc->sc_lock);
421 }
422
423 softint_disestablish(sc->sc_si);
424 mutex_exit(&sc->sc_lock);
425
426 /* locate the major number */
427 maj = cdevsw_lookup_major(&ucom_cdevsw);
428
429 /* Nuke the vnodes for any open instances. */
430 mn = device_unit(self);
431 DPRINTF("maj=%d mn=%d\n", maj, mn, 0, 0);
432 vdevgone(maj, mn, mn, VCHR);
433 vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
434 vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
435
436 /* Detach and free the tty. */
437 if (tp != NULL) {
438 tty_detach(tp);
439 tty_free(tp);
440 sc->sc_tty = NULL;
441 }
442
443 for (i = 0; i < UCOM_IN_BUFFS; i++) {
444 if (sc->sc_ibuff[i].ub_xfer != NULL)
445 usbd_destroy_xfer(sc->sc_ibuff[i].ub_xfer);
446 }
447
448 for (i = 0; i < UCOM_OUT_BUFFS; i++) {
449 if (sc->sc_obuff[i].ub_xfer != NULL)
450 usbd_destroy_xfer(sc->sc_obuff[i].ub_xfer);
451 }
452
453 if (sc->sc_bulkin_pipe != NULL) {
454 usbd_close_pipe(sc->sc_bulkin_pipe);
455 sc->sc_bulkin_pipe = NULL;
456 }
457
458 if (sc->sc_bulkout_pipe != NULL) {
459 usbd_close_pipe(sc->sc_bulkout_pipe);
460 sc->sc_bulkout_pipe = NULL;
461 }
462
463 /* Detach the random source */
464 rnd_detach_source(&sc->sc_rndsource);
465
466 mutex_destroy(&sc->sc_lock);
467 cv_destroy(&sc->sc_opencv);
468 cv_destroy(&sc->sc_detachcv);
469
470 return 0;
471 }
472
473 int
ucom_activate(device_t self,enum devact act)474 ucom_activate(device_t self, enum devact act)
475 {
476 struct ucom_softc *sc = device_private(self);
477
478 UCOMHIST_FUNC(); UCOMHIST_CALLED();
479
480 DPRINTFN(5, "%d", act, 0, 0, 0);
481
482 switch (act) {
483 case DVACT_DEACTIVATE:
484 mutex_enter(&sc->sc_lock);
485 sc->sc_dying = 1;
486 mutex_exit(&sc->sc_lock);
487 return 0;
488 default:
489 return EOPNOTSUPP;
490 }
491 }
492
493 void
ucom_shutdown(struct ucom_softc * sc)494 ucom_shutdown(struct ucom_softc *sc)
495 {
496 struct tty *tp = sc->sc_tty;
497
498 UCOMHIST_FUNC(); UCOMHIST_CALLED();
499
500 KASSERT(mutex_owned(&sc->sc_lock));
501 /*
502 * Hang up if necessary. Wait a bit, so the other side has time to
503 * notice even if we immediately open the port again.
504 */
505 if (ISSET(tp->t_cflag, HUPCL)) {
506 ucom_dtr(sc, 0);
507 /* XXX will only timeout */
508 (void) kpause(ttclos, false, hz, &sc->sc_lock);
509 }
510 }
511
512 int
ucomopen(dev_t dev,int flag,int mode,struct lwp * l)513 ucomopen(dev_t dev, int flag, int mode, struct lwp *l)
514 {
515 int unit = UCOMUNIT(dev);
516 struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
517 struct ucom_buffer *ub;
518 struct tty *tp;
519 int error;
520
521 UCOMHIST_FUNC(); UCOMHIST_CALLED();
522
523 if (sc == NULL)
524 return ENXIO;
525
526 mutex_enter(&sc->sc_lock);
527 if (sc->sc_dying) {
528 mutex_exit(&sc->sc_lock);
529 return EIO;
530 }
531
532 if (!device_is_active(sc->sc_dev)) {
533 mutex_exit(&sc->sc_lock);
534 return ENXIO;
535 }
536
537 tp = sc->sc_tty;
538
539 DPRINTF("unit=%d, tp=%p\n", unit, tp, 0, 0);
540
541 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
542 mutex_exit(&sc->sc_lock);
543 return EBUSY;
544 }
545
546 /*
547 * Wait while the device is initialized by the
548 * first opener or cleaned up by the last closer.
549 */
550 while (sc->sc_opening || sc->sc_closing) {
551 error = cv_wait_sig(&sc->sc_opencv, &sc->sc_lock);
552
553 if (error) {
554 mutex_exit(&sc->sc_lock);
555 return error;
556 }
557 }
558
559 sc->sc_opening = 1;
560
561 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
562 struct termios t;
563
564 tp->t_dev = dev;
565
566 if (sc->sc_methods->ucom_open != NULL) {
567 error = sc->sc_methods->ucom_open(sc->sc_parent,
568 sc->sc_portno);
569 if (error) {
570 ucom_cleanup(sc);
571 sc->sc_opening = 0;
572 cv_signal(&sc->sc_opencv);
573 mutex_exit(&sc->sc_lock);
574 return error;
575 }
576 }
577
578 ucom_status_change(sc);
579
580 /* Clear PPS capture state on first open. */
581 mutex_spin_enter(&timecounter_lock);
582 memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state));
583 sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
584 pps_init(&sc->sc_pps_state);
585 mutex_spin_exit(&timecounter_lock);
586
587 /*
588 * Initialize the termios status to the defaults. Add in the
589 * sticky bits from TIOCSFLAGS.
590 */
591 t.c_ispeed = 0;
592 t.c_ospeed = TTYDEF_SPEED;
593 t.c_cflag = TTYDEF_CFLAG;
594 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
595 SET(t.c_cflag, CLOCAL);
596 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
597 SET(t.c_cflag, CRTSCTS);
598 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
599 SET(t.c_cflag, MDMBUF);
600 /* Make sure ucomparam() will do something. */
601 tp->t_ospeed = 0;
602 (void) ucomparam(tp, &t);
603 tp->t_iflag = TTYDEF_IFLAG;
604 tp->t_oflag = TTYDEF_OFLAG;
605 tp->t_lflag = TTYDEF_LFLAG;
606 ttychars(tp);
607 ttsetwater(tp);
608
609 /*
610 * Turn on DTR. We must always do this, even if carrier is not
611 * present, because otherwise we'd have to use TIOCSDTR
612 * immediately after setting CLOCAL, which applications do not
613 * expect. We always assert DTR while the device is open
614 * unless explicitly requested to deassert it. Ditto RTS.
615 */
616 ucom_dtr(sc, 1);
617 ucom_rts(sc, 1);
618
619 sc->sc_rx_unblock = 0;
620 sc->sc_rx_stopped = 0;
621 sc->sc_tx_stopped = 0;
622
623 for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
624 ub++) {
625 if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) {
626 error = EIO;
627 goto fail_2;
628 }
629 }
630 }
631 sc->sc_opening = 0;
632 cv_signal(&sc->sc_opencv);
633 mutex_exit(&sc->sc_lock);
634
635 error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
636 if (error)
637 goto bad;
638
639 error = (*tp->t_linesw->l_open)(dev, tp);
640 if (error)
641 goto bad;
642
643 return 0;
644
645 fail_2:
646 usbd_abort_pipe(sc->sc_bulkin_pipe);
647 usbd_abort_pipe(sc->sc_bulkout_pipe);
648
649 mutex_enter(&sc->sc_lock);
650 sc->sc_opening = 0;
651 cv_signal(&sc->sc_opencv);
652 mutex_exit(&sc->sc_lock);
653
654 return error;
655
656 bad:
657 mutex_spin_enter(&tty_lock);
658 CLR(tp->t_state, TS_BUSY);
659 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
660 /*
661 * We failed to open the device, and nobody else had it opened.
662 * Clean up the state as appropriate.
663 */
664 ucom_cleanup(sc);
665 }
666 mutex_spin_exit(&tty_lock);
667
668 return error;
669 }
670
671 int
ucomclose(dev_t dev,int flag,int mode,struct lwp * l)672 ucomclose(dev_t dev, int flag, int mode, struct lwp *l)
673 {
674 struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
675 struct tty *tp;
676
677 UCOMHIST_FUNC(); UCOMHIST_CALLED();
678
679 DPRINTF("unit=%d", UCOMUNIT(dev), 0, 0, 0);
680
681 if (sc == NULL)
682 return 0;
683
684 mutex_enter(&sc->sc_lock);
685 tp = sc->sc_tty;
686
687 while (sc->sc_closing)
688 cv_wait(&sc->sc_opencv, &sc->sc_lock);
689 sc->sc_closing = 1;
690
691 if (!ISSET(tp->t_state, TS_ISOPEN)) {
692 goto out;
693 }
694
695 sc->sc_refcnt++;
696
697 (*tp->t_linesw->l_close)(tp, flag);
698 ttyclose(tp);
699
700 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
701 /*
702 * Although we got a last close, the device may still be in
703 * use; e.g. if this was the dialout node, and there are still
704 * processes waiting for carrier on the non-dialout node.
705 */
706 ucom_cleanup(sc);
707 }
708
709 if (sc->sc_methods->ucom_close != NULL)
710 sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
711
712 if (--sc->sc_refcnt < 0)
713 usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
714
715 out:
716 sc->sc_closing = 0;
717 cv_signal(&sc->sc_opencv);
718
719 mutex_exit(&sc->sc_lock);
720
721 return 0;
722 }
723
724 int
ucomread(dev_t dev,struct uio * uio,int flag)725 ucomread(dev_t dev, struct uio *uio, int flag)
726 {
727 struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
728 struct tty *tp;
729 int error;
730
731 UCOMHIST_FUNC(); UCOMHIST_CALLED();
732
733 if (sc == NULL)
734 return EIO;
735
736 mutex_enter(&sc->sc_lock);
737 if (sc->sc_dying) {
738 mutex_exit(&sc->sc_lock);
739 return EIO;
740 }
741
742 tp = sc->sc_tty;
743
744 sc->sc_refcnt++;
745 mutex_exit(&sc->sc_lock);
746 error = ((*tp->t_linesw->l_read)(tp, uio, flag));
747 mutex_enter(&sc->sc_lock);
748
749 if (--sc->sc_refcnt < 0)
750 usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
751 mutex_exit(&sc->sc_lock);
752
753 return error;
754 }
755
756 int
ucomwrite(dev_t dev,struct uio * uio,int flag)757 ucomwrite(dev_t dev, struct uio *uio, int flag)
758 {
759 struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
760 struct tty *tp;
761 int error;
762
763 if (sc == NULL)
764 return EIO;
765
766 mutex_enter(&sc->sc_lock);
767 if (sc->sc_dying) {
768 mutex_exit(&sc->sc_lock);
769 return EIO;
770 }
771
772 tp = sc->sc_tty;
773
774 sc->sc_refcnt++;
775 mutex_exit(&sc->sc_lock);
776 error = ((*tp->t_linesw->l_write)(tp, uio, flag));
777 mutex_enter(&sc->sc_lock);
778 if (--sc->sc_refcnt < 0)
779 usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
780 mutex_exit(&sc->sc_lock);
781
782 return error;
783 }
784
785 int
ucompoll(dev_t dev,int events,struct lwp * l)786 ucompoll(dev_t dev, int events, struct lwp *l)
787 {
788 struct ucom_softc *sc;
789 struct tty *tp;
790 int revents;
791
792 sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
793 if (sc == NULL)
794 return POLLHUP;
795
796 mutex_enter(&sc->sc_lock);
797 if (sc->sc_dying) {
798 mutex_exit(&sc->sc_lock);
799 return POLLHUP;
800 }
801 tp = sc->sc_tty;
802
803 sc->sc_refcnt++;
804 mutex_exit(&sc->sc_lock);
805 revents = ((*tp->t_linesw->l_poll)(tp, events, l));
806 mutex_enter(&sc->sc_lock);
807 if (--sc->sc_refcnt < 0)
808 usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
809 mutex_exit(&sc->sc_lock);
810
811 return revents;
812 }
813
814 struct tty *
ucomtty(dev_t dev)815 ucomtty(dev_t dev)
816 {
817 struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
818
819 return sc != NULL ? sc->sc_tty : NULL;
820 }
821
822 int
ucomioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)823 ucomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
824 {
825 struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
826 int error;
827
828 if (sc == NULL)
829 return EIO;
830
831 mutex_enter(&sc->sc_lock);
832 if (sc->sc_dying) {
833 mutex_exit(&sc->sc_lock);
834 return EIO;
835 }
836
837 sc->sc_refcnt++;
838 error = ucom_do_ioctl(sc, cmd, data, flag, l);
839 if (--sc->sc_refcnt < 0)
840 usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
841 mutex_exit(&sc->sc_lock);
842 return error;
843 }
844
845 static int
ucom_do_ioctl(struct ucom_softc * sc,u_long cmd,void * data,int flag,struct lwp * l)846 ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, void *data,
847 int flag, struct lwp *l)
848 {
849 struct tty *tp = sc->sc_tty;
850 int error;
851
852 UCOMHIST_FUNC(); UCOMHIST_CALLED();
853
854 DPRINTF("cmd=0x%08lx", cmd, 0, 0, 0);
855
856 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
857 if (error != EPASSTHROUGH)
858 return error;
859
860 error = ttioctl(tp, cmd, data, flag, l);
861 if (error != EPASSTHROUGH)
862 return error;
863
864 if (sc->sc_methods->ucom_ioctl != NULL) {
865 error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
866 sc->sc_portno, cmd, data, flag, l->l_proc);
867 if (error != EPASSTHROUGH)
868 return error;
869 }
870
871 error = 0;
872
873 DPRINTF("our cmd=0x%08lx", cmd, 0, 0, 0);
874 //mutex_enter(&tty_lock);
875
876 switch (cmd) {
877 case TIOCSBRK:
878 ucom_break(sc, 1);
879 break;
880
881 case TIOCCBRK:
882 ucom_break(sc, 0);
883 break;
884
885 case TIOCSDTR:
886 ucom_dtr(sc, 1);
887 break;
888
889 case TIOCCDTR:
890 ucom_dtr(sc, 0);
891 break;
892
893 case TIOCGFLAGS:
894 *(int *)data = sc->sc_swflags;
895 break;
896
897 case TIOCSFLAGS:
898 error = kauth_authorize_device_tty(l->l_cred,
899 KAUTH_DEVICE_TTY_PRIVSET, tp);
900 if (error)
901 break;
902 sc->sc_swflags = *(int *)data;
903 break;
904
905 case TIOCMSET:
906 case TIOCMBIS:
907 case TIOCMBIC:
908 tiocm_to_ucom(sc, cmd, *(int *)data);
909 break;
910
911 case TIOCMGET:
912 *(int *)data = ucom_to_tiocm(sc);
913 break;
914
915 case PPS_IOC_CREATE:
916 case PPS_IOC_DESTROY:
917 case PPS_IOC_GETPARAMS:
918 case PPS_IOC_SETPARAMS:
919 case PPS_IOC_GETCAP:
920 case PPS_IOC_FETCH:
921 #ifdef PPS_SYNC
922 case PPS_IOC_KCBIND:
923 #endif
924 mutex_spin_enter(&timecounter_lock);
925 error = pps_ioctl(cmd, data, &sc->sc_pps_state);
926 mutex_spin_exit(&timecounter_lock);
927 break;
928
929 default:
930 error = EPASSTHROUGH;
931 break;
932 }
933
934 //mutex_exit(&tty_lock);
935
936 return error;
937 }
938
939 static void
tiocm_to_ucom(struct ucom_softc * sc,u_long how,int ttybits)940 tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
941 {
942 u_char combits;
943
944 combits = 0;
945 if (ISSET(ttybits, TIOCM_DTR))
946 SET(combits, UMCR_DTR);
947 if (ISSET(ttybits, TIOCM_RTS))
948 SET(combits, UMCR_RTS);
949
950 switch (how) {
951 case TIOCMBIC:
952 CLR(sc->sc_mcr, combits);
953 break;
954
955 case TIOCMBIS:
956 SET(sc->sc_mcr, combits);
957 break;
958
959 case TIOCMSET:
960 CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
961 SET(sc->sc_mcr, combits);
962 break;
963 }
964
965 if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
966 ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
967 if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
968 ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
969 }
970
971 static int
ucom_to_tiocm(struct ucom_softc * sc)972 ucom_to_tiocm(struct ucom_softc *sc)
973 {
974 u_char combits;
975 int ttybits = 0;
976
977 combits = sc->sc_mcr;
978 if (ISSET(combits, UMCR_DTR))
979 SET(ttybits, TIOCM_DTR);
980 if (ISSET(combits, UMCR_RTS))
981 SET(ttybits, TIOCM_RTS);
982
983 combits = sc->sc_msr;
984 if (ISSET(combits, UMSR_DCD))
985 SET(ttybits, TIOCM_CD);
986 if (ISSET(combits, UMSR_CTS))
987 SET(ttybits, TIOCM_CTS);
988 if (ISSET(combits, UMSR_DSR))
989 SET(ttybits, TIOCM_DSR);
990 if (ISSET(combits, UMSR_RI | UMSR_TERI))
991 SET(ttybits, TIOCM_RI);
992
993 #if 0
994 XXX;
995 if (sc->sc_ier != 0)
996 SET(ttybits, TIOCM_LE);
997 #endif
998
999 return ttybits;
1000 }
1001
1002 static void
ucom_break(struct ucom_softc * sc,int onoff)1003 ucom_break(struct ucom_softc *sc, int onoff)
1004 {
1005 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1006
1007 DPRINTF("onoff=%d", onoff, 0, 0, 0);
1008
1009 if (sc->sc_methods->ucom_set != NULL)
1010 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1011 UCOM_SET_BREAK, onoff);
1012 }
1013
1014 static void
ucom_dtr(struct ucom_softc * sc,int onoff)1015 ucom_dtr(struct ucom_softc *sc, int onoff)
1016 {
1017 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1018
1019 DPRINTF("onoff=%d", onoff, 0, 0, 0);
1020
1021 if (sc->sc_methods->ucom_set != NULL)
1022 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1023 UCOM_SET_DTR, onoff);
1024 }
1025
1026 static void
ucom_rts(struct ucom_softc * sc,int onoff)1027 ucom_rts(struct ucom_softc *sc, int onoff)
1028 {
1029 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1030
1031 DPRINTF("onoff=%d", onoff, 0, 0, 0);
1032
1033 if (sc->sc_methods->ucom_set != NULL)
1034 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1035 UCOM_SET_RTS, onoff);
1036 }
1037
1038 void
ucom_status_change(struct ucom_softc * sc)1039 ucom_status_change(struct ucom_softc *sc)
1040 {
1041 struct tty *tp = sc->sc_tty;
1042 u_char old_msr;
1043
1044 if (sc->sc_methods->ucom_get_status != NULL) {
1045 old_msr = sc->sc_msr;
1046 sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
1047 &sc->sc_lsr, &sc->sc_msr);
1048 if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
1049 mutex_spin_enter(&timecounter_lock);
1050 pps_capture(&sc->sc_pps_state);
1051 pps_event(&sc->sc_pps_state,
1052 (sc->sc_msr & UMSR_DCD) ?
1053 PPS_CAPTUREASSERT :
1054 PPS_CAPTURECLEAR);
1055 mutex_spin_exit(&timecounter_lock);
1056
1057 (*tp->t_linesw->l_modem)(tp,
1058 ISSET(sc->sc_msr, UMSR_DCD));
1059 }
1060 } else {
1061 sc->sc_lsr = 0;
1062 /* Assume DCD is present, if we have no chance to check it. */
1063 sc->sc_msr = UMSR_DCD;
1064 }
1065 }
1066
1067 static int
ucomparam(struct tty * tp,struct termios * t)1068 ucomparam(struct tty *tp, struct termios *t)
1069 {
1070 struct ucom_softc *sc = device_lookup_private(&ucom_cd,
1071 UCOMUNIT(tp->t_dev));
1072 int error;
1073
1074 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1075
1076 if (sc == NULL || sc->sc_dying)
1077 return EIO;
1078
1079 /* Check requested parameters. */
1080 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
1081 return EINVAL;
1082
1083 /*
1084 * For the console, always force CLOCAL and !HUPCL, so that the port
1085 * is always active.
1086 */
1087 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
1088 SET(t->c_cflag, CLOCAL);
1089 CLR(t->c_cflag, HUPCL);
1090 }
1091
1092 /*
1093 * If there were no changes, don't do anything. This avoids dropping
1094 * input and improves performance when all we did was frob things like
1095 * VMIN and VTIME.
1096 */
1097 if (tp->t_ospeed == t->c_ospeed &&
1098 tp->t_cflag == t->c_cflag)
1099 return 0;
1100
1101 /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
1102
1103 /* And copy to tty. */
1104 tp->t_ispeed = 0;
1105 tp->t_ospeed = t->c_ospeed;
1106 tp->t_cflag = t->c_cflag;
1107
1108 if (sc->sc_methods->ucom_param != NULL) {
1109 error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
1110 t);
1111 if (error)
1112 return error;
1113 }
1114
1115 /* XXX worry about CHWFLOW */
1116
1117 /*
1118 * Update the tty layer's idea of the carrier bit, in case we changed
1119 * CLOCAL or MDMBUF. We don't hang up here; we only do that by
1120 * explicit request.
1121 */
1122 DPRINTF("l_modem", 0, 0, 0, 0);
1123 (void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, UMSR_DCD));
1124
1125 #if 0
1126 XXX what if the hardware is not open
1127 if (!ISSET(t->c_cflag, CHWFLOW)) {
1128 if (sc->sc_tx_stopped) {
1129 sc->sc_tx_stopped = 0;
1130 ucomstart(tp);
1131 }
1132 }
1133 #endif
1134
1135 return 0;
1136 }
1137
1138 static int
ucomhwiflow(struct tty * tp,int block)1139 ucomhwiflow(struct tty *tp, int block)
1140 {
1141 struct ucom_softc *sc = device_lookup_private(&ucom_cd,
1142 UCOMUNIT(tp->t_dev));
1143 int old;
1144
1145 if (sc == NULL)
1146 return 0;
1147
1148 mutex_enter(&sc->sc_lock);
1149 old = sc->sc_rx_stopped;
1150 sc->sc_rx_stopped = (u_char)block;
1151
1152 if (old && !block) {
1153 sc->sc_rx_unblock = 1;
1154 softint_schedule(sc->sc_si);
1155 }
1156 mutex_exit(&sc->sc_lock);
1157
1158 return 1;
1159 }
1160
1161 static void
ucomstart(struct tty * tp)1162 ucomstart(struct tty *tp)
1163 {
1164 struct ucom_softc *sc = device_lookup_private(&ucom_cd,
1165 UCOMUNIT(tp->t_dev));
1166 struct ucom_buffer *ub;
1167 u_char *data;
1168 int cnt;
1169
1170 if (sc == NULL)
1171 return;
1172
1173 KASSERT(&sc->sc_lock);
1174 KASSERT(mutex_owned(&tty_lock));
1175 if (sc->sc_dying) {
1176 return;
1177 }
1178
1179 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1180 goto out;
1181 if (sc->sc_tx_stopped)
1182 goto out;
1183
1184 if (!ttypull(tp))
1185 goto out;
1186
1187 /* Grab the first contiguous region of buffer space. */
1188 data = tp->t_outq.c_cf;
1189 cnt = ndqb(&tp->t_outq, 0);
1190
1191 if (cnt == 0)
1192 goto out;
1193
1194 ub = SIMPLEQ_FIRST(&sc->sc_obuff_free);
1195 if (ub == NULL) {
1196 SET(tp->t_state, TS_BUSY);
1197 goto out;
1198 }
1199
1200 SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_free, ub_link);
1201
1202 if (SIMPLEQ_FIRST(&sc->sc_obuff_free) == NULL)
1203 SET(tp->t_state, TS_BUSY);
1204
1205 if (cnt > sc->sc_obufsize)
1206 cnt = sc->sc_obufsize;
1207
1208 if (sc->sc_methods->ucom_write != NULL)
1209 sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
1210 ub->ub_data, data, &cnt);
1211 else
1212 memcpy(ub->ub_data, data, cnt);
1213
1214 ub->ub_len = cnt;
1215 ub->ub_index = 0;
1216
1217 SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_full, ub, ub_link);
1218
1219 softint_schedule(sc->sc_si);
1220
1221 out:
1222 return;
1223 }
1224
1225 void
ucomstop(struct tty * tp,int flag)1226 ucomstop(struct tty *tp, int flag)
1227 {
1228 #if 0
1229 struct ucom_softc *sc =
1230 device_lookup_private(&ucom_cd, UCOMUNIT(tp->t_dev));
1231
1232 mutex_enter(&sc->sc_lock);
1233 mutex_spin_enter(&tty_lock);
1234 if (ISSET(tp->t_state, TS_BUSY)) {
1235 /* obuff_full -> obuff_free? */
1236 /* sc->sc_tx_stopped = 1; */
1237 if (!ISSET(tp->t_state, TS_TTSTOP))
1238 SET(tp->t_state, TS_FLUSH);
1239 }
1240 mutex_spin_exit(&tty_lock);
1241 mutex_exit(&sc->sc_lock);
1242 #endif
1243 }
1244
1245 static void
ucom_write_status(struct ucom_softc * sc,struct ucom_buffer * ub,usbd_status err)1246 ucom_write_status(struct ucom_softc *sc, struct ucom_buffer *ub,
1247 usbd_status err)
1248 {
1249 struct tty *tp = sc->sc_tty;
1250 uint32_t cc = ub->ub_len;
1251
1252 KASSERT(mutex_owned(&sc->sc_lock));
1253
1254 switch (err) {
1255 case USBD_IN_PROGRESS:
1256 ub->ub_index = ub->ub_len;
1257 break;
1258 case USBD_STALLED:
1259 ub->ub_index = 0;
1260 softint_schedule(sc->sc_si);
1261 break;
1262 case USBD_NORMAL_COMPLETION:
1263 usbd_get_xfer_status(ub->ub_xfer, NULL, NULL, &cc, NULL);
1264 rnd_add_uint32(&sc->sc_rndsource, cc);
1265 /*FALLTHROUGH*/
1266 default:
1267 SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_full, ub_link);
1268 SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
1269 cc -= sc->sc_opkthdrlen;
1270
1271 mutex_spin_enter(&tty_lock);
1272 CLR(tp->t_state, TS_BUSY);
1273 if (ISSET(tp->t_state, TS_FLUSH))
1274 CLR(tp->t_state, TS_FLUSH);
1275 else
1276 ndflush(&tp->t_outq, cc);
1277 mutex_spin_exit(&tty_lock);
1278
1279 if (err != USBD_CANCELLED && err != USBD_IOERROR &&
1280 !sc->sc_dying) {
1281 if ((ub = SIMPLEQ_FIRST(&sc->sc_obuff_full)) != NULL)
1282 ucom_submit_write(sc, ub);
1283
1284 mutex_spin_enter(&tty_lock);
1285 (*tp->t_linesw->l_start)(tp);
1286 mutex_spin_exit(&tty_lock);
1287 }
1288 break;
1289 }
1290 }
1291
1292 static void
ucom_submit_write(struct ucom_softc * sc,struct ucom_buffer * ub)1293 ucom_submit_write(struct ucom_softc *sc, struct ucom_buffer *ub)
1294 {
1295
1296 KASSERT(mutex_owned(&sc->sc_lock));
1297
1298 usbd_setup_xfer(ub->ub_xfer, sc, ub->ub_data, ub->ub_len,
1299 0, USBD_NO_TIMEOUT, ucomwritecb);
1300
1301 ucom_write_status(sc, ub, usbd_transfer(ub->ub_xfer));
1302 }
1303
1304 static void
ucomwritecb(struct usbd_xfer * xfer,void * p,usbd_status status)1305 ucomwritecb(struct usbd_xfer *xfer, void *p, usbd_status status)
1306 {
1307 struct ucom_softc *sc = (struct ucom_softc *)p;
1308
1309 mutex_enter(&sc->sc_lock);
1310 ucom_write_status(sc, SIMPLEQ_FIRST(&sc->sc_obuff_full), status);
1311 mutex_exit(&sc->sc_lock);
1312
1313 }
1314
1315 static void
ucom_softintr(void * arg)1316 ucom_softintr(void *arg)
1317 {
1318 struct ucom_softc *sc = arg;
1319 struct tty *tp = sc->sc_tty;
1320 struct ucom_buffer *ub;
1321
1322 mutex_enter(&sc->sc_lock);
1323 mutex_enter(&tty_lock);
1324 if (!ISSET(tp->t_state, TS_ISOPEN)) {
1325 mutex_exit(&tty_lock);
1326 mutex_exit(&sc->sc_lock);
1327 return;
1328 }
1329 mutex_exit(&tty_lock);
1330
1331 ub = SIMPLEQ_FIRST(&sc->sc_obuff_full);
1332
1333 if (ub != NULL && ub->ub_index == 0)
1334 ucom_submit_write(sc, ub);
1335
1336 if (sc->sc_rx_unblock)
1337 ucom_read_complete(sc);
1338
1339 mutex_exit(&sc->sc_lock);
1340 }
1341
1342 static void
ucom_read_complete(struct ucom_softc * sc)1343 ucom_read_complete(struct ucom_softc *sc)
1344 {
1345 int (*rint)(int, struct tty *);
1346 struct ucom_buffer *ub;
1347 struct tty *tp;
1348
1349 KASSERT(mutex_owned(&sc->sc_lock));
1350
1351 tp = sc->sc_tty;
1352 rint = tp->t_linesw->l_rint;
1353 ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
1354
1355 while (ub != NULL && !sc->sc_rx_stopped) {
1356
1357 /* XXX ttyinput takes tty_lock */
1358 while (ub->ub_index < ub->ub_len && !sc->sc_rx_stopped) {
1359 /* Give characters to tty layer. */
1360 if ((*rint)(ub->ub_data[ub->ub_index], tp) == -1) {
1361 /* Overflow: drop remainder */
1362 ub->ub_index = ub->ub_len;
1363 } else
1364 ub->ub_index++;
1365 }
1366
1367 if (ub->ub_index == ub->ub_len) {
1368 SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link);
1369
1370 ucomsubmitread(sc, ub);
1371
1372 ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
1373 }
1374 }
1375
1376 sc->sc_rx_unblock = (ub != NULL);
1377 }
1378
1379 static usbd_status
ucomsubmitread(struct ucom_softc * sc,struct ucom_buffer * ub)1380 ucomsubmitread(struct ucom_softc *sc, struct ucom_buffer *ub)
1381 {
1382 usbd_status err;
1383
1384 usbd_setup_xfer(ub->ub_xfer, sc, ub->ub_data, sc->sc_ibufsize,
1385 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, ucomreadcb);
1386
1387 if ((err = usbd_transfer(ub->ub_xfer)) != USBD_IN_PROGRESS) {
1388 /* XXX: Recover from this, please! */
1389 printf("ucomsubmitread: err=%s\n", usbd_errstr(err));
1390 return err;
1391 }
1392
1393 SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_empty, ub, ub_link);
1394
1395 return USBD_NORMAL_COMPLETION;
1396 }
1397
1398 static void
ucomreadcb(struct usbd_xfer * xfer,void * p,usbd_status status)1399 ucomreadcb(struct usbd_xfer *xfer, void *p, usbd_status status)
1400 {
1401 struct ucom_softc *sc = (struct ucom_softc *)p;
1402 struct tty *tp = sc->sc_tty;
1403 struct ucom_buffer *ub;
1404 uint32_t cc;
1405 u_char *cp;
1406
1407 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1408
1409 if (status == USBD_CANCELLED)
1410 return;
1411
1412 mutex_enter(&sc->sc_lock);
1413 if (status == USBD_IOERROR ||
1414 sc->sc_dying) {
1415 DPRINTF("dying", 0, 0, 0, 0);
1416 /* Send something to wake upper layer */
1417 (tp->t_linesw->l_rint)('\n', tp);
1418 mutex_spin_enter(&tty_lock); /* XXX */
1419 ttwakeup(tp);
1420 mutex_spin_exit(&tty_lock); /* XXX */
1421 mutex_exit(&sc->sc_lock);
1422 return;
1423 }
1424
1425 ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
1426 SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
1427
1428 if (status == USBD_STALLED) {
1429 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1430 ucomsubmitread(sc, ub);
1431 mutex_exit(&sc->sc_lock);
1432 return;
1433 }
1434
1435 if (status != USBD_NORMAL_COMPLETION) {
1436 printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
1437 mutex_exit(&sc->sc_lock);
1438 return;
1439 }
1440
1441 usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
1442
1443 #ifdef UCOM_DEBUG
1444 /* This is triggered by uslsa(4) occasionally. */
1445 if ((ucomdebug > 0) && (cc == 0)) {
1446 device_printf(sc->sc_dev, "ucomreadcb: zero length xfer!\n");
1447 }
1448 #endif
1449
1450 KDASSERT(cp == ub->ub_data);
1451
1452 rnd_add_uint32(&sc->sc_rndsource, cc);
1453
1454 if (sc->sc_opening) {
1455 ucomsubmitread(sc, ub);
1456 mutex_exit(&sc->sc_lock);
1457 return;
1458 }
1459
1460 if (sc->sc_methods->ucom_read != NULL) {
1461 sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
1462 &cp, &cc);
1463 ub->ub_index = (u_int)(cp - ub->ub_data);
1464 } else
1465 ub->ub_index = 0;
1466
1467 ub->ub_len = cc;
1468
1469 SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link);
1470
1471 ucom_read_complete(sc);
1472 mutex_exit(&sc->sc_lock);
1473 }
1474
1475 static void
ucom_cleanup(struct ucom_softc * sc)1476 ucom_cleanup(struct ucom_softc *sc)
1477 {
1478
1479 UCOMHIST_FUNC(); UCOMHIST_CALLED();
1480
1481 DPRINTF("aborting pipes", 0, 0, 0, 0);
1482
1483 KASSERT(mutex_owned(&sc->sc_lock));
1484
1485 ucom_shutdown(sc);
1486 if (sc->sc_bulkin_pipe != NULL) {
1487 usbd_abort_pipe(sc->sc_bulkin_pipe);
1488 }
1489 if (sc->sc_bulkout_pipe != NULL) {
1490 usbd_abort_pipe(sc->sc_bulkout_pipe);
1491 }
1492 }
1493
1494 #endif /* NUCOM > 0 */
1495
1496 int
ucomprint(void * aux,const char * pnp)1497 ucomprint(void *aux, const char *pnp)
1498 {
1499 struct ucom_attach_args *ucaa = aux;
1500
1501 if (pnp)
1502 aprint_normal("ucom at %s", pnp);
1503 if (ucaa->ucaa_portno != UCOM_UNK_PORTNO)
1504 aprint_normal(" portno %d", ucaa->ucaa_portno);
1505 return UNCONF;
1506 }
1507
1508 int
ucomsubmatch(device_t parent,cfdata_t cf,const int * ldesc,void * aux)1509 ucomsubmatch(device_t parent, cfdata_t cf,
1510 const int *ldesc, void *aux)
1511 {
1512 struct ucom_attach_args *ucaa = aux;
1513
1514 if (ucaa->ucaa_portno != UCOM_UNK_PORTNO &&
1515 cf->cf_loc[UCOMBUSCF_PORTNO] != UCOMBUSCF_PORTNO_DEFAULT &&
1516 cf->cf_loc[UCOMBUSCF_PORTNO] != ucaa->ucaa_portno)
1517 return 0;
1518 return config_match(parent, cf, aux);
1519 }
1520