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