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