usb_serial.c revision 217265
1/*	$NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $	*/
2
3/*-
4 * Copyright (c) 2001-2003, 2005, 2008
5 *	Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/usb/serial/usb_serial.c 217265 2011-01-11 13:59:06Z jhb $");
32
33/*-
34 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 *    must display the following acknowledgement:
51 *        This product includes software developed by the NetBSD
52 *        Foundation, Inc. and its contributors.
53 * 4. Neither the name of The NetBSD Foundation nor the names of its
54 *    contributors may be used to endorse or promote products derived
55 *    from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67 * POSSIBILITY OF SUCH DAMAGE.
68 */
69
70#include <sys/stdint.h>
71#include <sys/stddef.h>
72#include <sys/param.h>
73#include <sys/queue.h>
74#include <sys/types.h>
75#include <sys/systm.h>
76#include <sys/kernel.h>
77#include <sys/bus.h>
78#include <sys/module.h>
79#include <sys/lock.h>
80#include <sys/mutex.h>
81#include <sys/condvar.h>
82#include <sys/sysctl.h>
83#include <sys/sx.h>
84#include <sys/unistd.h>
85#include <sys/callout.h>
86#include <sys/malloc.h>
87#include <sys/priv.h>
88#include <sys/cons.h>
89#include <sys/kdb.h>
90
91#include <dev/usb/usb.h>
92#include <dev/usb/usbdi.h>
93#include <dev/usb/usbdi_util.h>
94
95#define	USB_DEBUG_VAR ucom_debug
96#include <dev/usb/usb_debug.h>
97#include <dev/usb/usb_busdma.h>
98#include <dev/usb/usb_process.h>
99
100#include <dev/usb/serial/usb_serial.h>
101
102#include "opt_gdb.h"
103
104SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
105
106#ifdef USB_DEBUG
107static int ucom_debug = 0;
108
109SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
110    &ucom_debug, 0, "ucom debug level");
111#endif
112
113#define	UCOM_CONS_BUFSIZE 1024
114
115static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
116static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
117
118static unsigned int ucom_cons_rx_low = 0;
119static unsigned int ucom_cons_rx_high = 0;
120
121static unsigned int ucom_cons_tx_low = 0;
122static unsigned int ucom_cons_tx_high = 0;
123
124static int ucom_cons_unit = -1;
125static int ucom_cons_subunit = 0;
126static int ucom_cons_baud = 9600;
127static struct ucom_softc *ucom_cons_softc = NULL;
128
129TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
130SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
131    &ucom_cons_unit, 0, "console unit number");
132TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit);
133SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW,
134    &ucom_cons_subunit, 0, "console subunit number");
135TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
136SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
137    &ucom_cons_baud, 0, "console baud rate");
138
139static usb_proc_callback_t ucom_cfg_start_transfers;
140static usb_proc_callback_t ucom_cfg_open;
141static usb_proc_callback_t ucom_cfg_close;
142static usb_proc_callback_t ucom_cfg_line_state;
143static usb_proc_callback_t ucom_cfg_status_change;
144static usb_proc_callback_t ucom_cfg_param;
145
146static int	ucom_unit_alloc(void);
147static void	ucom_unit_free(int);
148static int	ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
149static void	ucom_detach_tty(struct ucom_softc *);
150static void	ucom_queue_command(struct ucom_softc *,
151		    usb_proc_callback_t *, struct termios *pt,
152		    struct usb_proc_msg *t0, struct usb_proc_msg *t1);
153static void	ucom_shutdown(struct ucom_softc *);
154static void	ucom_ring(struct ucom_softc *, uint8_t);
155static void	ucom_break(struct ucom_softc *, uint8_t);
156static void	ucom_dtr(struct ucom_softc *, uint8_t);
157static void	ucom_rts(struct ucom_softc *, uint8_t);
158
159static tsw_open_t ucom_open;
160static tsw_close_t ucom_close;
161static tsw_ioctl_t ucom_ioctl;
162static tsw_modem_t ucom_modem;
163static tsw_param_t ucom_param;
164static tsw_outwakeup_t ucom_outwakeup;
165static tsw_free_t ucom_free;
166
167static struct ttydevsw ucom_class = {
168	.tsw_flags = TF_INITLOCK | TF_CALLOUT,
169	.tsw_open = ucom_open,
170	.tsw_close = ucom_close,
171	.tsw_outwakeup = ucom_outwakeup,
172	.tsw_ioctl = ucom_ioctl,
173	.tsw_param = ucom_param,
174	.tsw_modem = ucom_modem,
175	.tsw_free = ucom_free,
176};
177
178MODULE_DEPEND(ucom, usb, 1, 1, 1);
179MODULE_VERSION(ucom, 1);
180
181#define	UCOM_UNIT_MAX 		128	/* limits size of ucom_bitmap */
182
183static uint8_t ucom_bitmap[(UCOM_UNIT_MAX + 7) / 8];
184static struct mtx ucom_bitmap_mtx;
185MTX_SYSINIT(ucom_bitmap_mtx, &ucom_bitmap_mtx, "ucom bitmap", MTX_DEF);
186
187#define UCOM_TTY_PREFIX		"U"
188
189/*
190 * Mark a unit number (the X in cuaUX) as in use.
191 *
192 * Note that devices using a different naming scheme (see ucom_tty_name()
193 * callback) still use this unit allocation.
194 */
195static int
196ucom_unit_alloc(void)
197{
198	int unit;
199
200	mtx_lock(&ucom_bitmap_mtx);
201
202	for (unit = 0; unit < UCOM_UNIT_MAX; unit++) {
203		if ((ucom_bitmap[unit / 8] & (1 << (unit % 8))) == 0) {
204			ucom_bitmap[unit / 8] |= (1 << (unit % 8));
205			break;
206		}
207	}
208
209	mtx_unlock(&ucom_bitmap_mtx);
210
211	if (unit == UCOM_UNIT_MAX)
212		return -1;
213	else
214		return unit;
215}
216
217/*
218 * Mark the unit number as not in use.
219 */
220static void
221ucom_unit_free(int unit)
222{
223	mtx_lock(&ucom_bitmap_mtx);
224
225	ucom_bitmap[unit / 8] &= ~(1 << (unit % 8));
226
227	mtx_unlock(&ucom_bitmap_mtx);
228}
229
230/*
231 * Setup a group of one or more serial ports.
232 *
233 * The mutex pointed to by "mtx" is applied before all
234 * callbacks are called back. Also "mtx" must be applied
235 * before calling into the ucom-layer!
236 */
237int
238ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
239    uint32_t subunits, void *parent,
240    const struct ucom_callback *callback, struct mtx *mtx)
241{
242	uint32_t subunit;
243	int error = 0;
244
245	if ((sc == NULL) ||
246	    (subunits == 0) ||
247	    (callback == NULL)) {
248		return (EINVAL);
249	}
250
251	ssc->sc_unit = ucom_unit_alloc();
252	if (ssc->sc_unit == -1)
253		return (ENOMEM);
254
255	error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
256	if (error) {
257		ucom_unit_free(ssc->sc_unit);
258		return (error);
259	}
260	ssc->sc_subunits = subunits;
261
262	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
263		sc[subunit].sc_subunit = subunit;
264		sc[subunit].sc_super = ssc;
265		sc[subunit].sc_mtx = mtx;
266		sc[subunit].sc_parent = parent;
267		sc[subunit].sc_callback = callback;
268
269		error = ucom_attach_tty(ssc, &sc[subunit]);
270		if (error) {
271			ucom_detach(ssc, &sc[0]);
272			return (error);
273		}
274		sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
275	}
276
277	DPRINTF("tp = %p, unit = %d, subunits = %d\n",
278		sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
279
280	return (0);
281}
282
283/*
284 * NOTE: the following function will do nothing if
285 * the structure pointed to by "ssc" and "sc" is zero.
286 */
287void
288ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
289{
290	uint32_t subunit;
291
292	usb_proc_drain(&ssc->sc_tq);
293
294	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
295		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
296
297			ucom_detach_tty(&sc[subunit]);
298
299			/* avoid duplicate detach */
300			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
301		}
302	}
303	ucom_unit_free(ssc->sc_unit);
304	usb_proc_free(&ssc->sc_tq);
305}
306
307static int
308ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
309{
310	struct tty *tp;
311	char buf[32];			/* temporary TTY device name buffer */
312
313	tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
314	if (tp == NULL)
315		return (ENOMEM);
316
317	/* Check if the client has a custom TTY name */
318	buf[0] = '\0';
319	if (sc->sc_callback->ucom_tty_name) {
320		sc->sc_callback->ucom_tty_name(sc, buf,
321		    sizeof(buf), ssc->sc_unit, sc->sc_subunit);
322	}
323	if (buf[0] == 0) {
324		/* Use default TTY name */
325		if (ssc->sc_subunits > 1) {
326			/* multiple modems in one */
327			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u",
328			    ssc->sc_unit, sc->sc_subunit);
329		} else {
330			/* single modem */
331			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
332			    ssc->sc_unit);
333		}
334	}
335	tty_makedev(tp, NULL, "%s", buf);
336
337	sc->sc_tty = tp;
338
339	DPRINTF("ttycreate: %s\n", buf);
340	cv_init(&sc->sc_cv, "ucom");
341
342	/* Check if this device should be a console */
343	if ((ucom_cons_softc == NULL) &&
344	    (ssc->sc_unit == ucom_cons_unit) &&
345	    (sc->sc_subunit == ucom_cons_subunit)) {
346		struct termios t;
347
348		DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit);
349
350		ucom_cons_softc = sc;
351
352		memset(&t, 0, sizeof(t));
353		t.c_ispeed = ucom_cons_baud;
354		t.c_ospeed = t.c_ispeed;
355		t.c_cflag = CS8;
356
357		mtx_lock(ucom_cons_softc->sc_mtx);
358		ucom_cons_rx_low = 0;
359		ucom_cons_rx_high = 0;
360		ucom_cons_tx_low = 0;
361		ucom_cons_tx_high = 0;
362		sc->sc_flag |= UCOM_FLAG_CONSOLE;
363		ucom_open(ucom_cons_softc->sc_tty);
364		ucom_param(ucom_cons_softc->sc_tty, &t);
365		mtx_unlock(ucom_cons_softc->sc_mtx);
366	}
367
368	return (0);
369}
370
371static void
372ucom_detach_tty(struct ucom_softc *sc)
373{
374	struct tty *tp = sc->sc_tty;
375
376	DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
377
378	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
379		mtx_lock(ucom_cons_softc->sc_mtx);
380		ucom_close(ucom_cons_softc->sc_tty);
381		sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
382		mtx_unlock(ucom_cons_softc->sc_mtx);
383		ucom_cons_softc = NULL;
384	}
385
386	/* the config thread has been stopped when we get here */
387
388	mtx_lock(sc->sc_mtx);
389	sc->sc_flag |= UCOM_FLAG_GONE;
390	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
391	mtx_unlock(sc->sc_mtx);
392	if (tp) {
393		tty_lock(tp);
394
395		ucom_close(tp);	/* close, if any */
396
397		tty_rel_gone(tp);
398
399		mtx_lock(sc->sc_mtx);
400		/* Wait for the callback after the TTY is torn down */
401		while (sc->sc_ttyfreed == 0)
402			cv_wait(&sc->sc_cv, sc->sc_mtx);
403		/*
404		 * make sure that read and write transfers are stopped
405		 */
406		if (sc->sc_callback->ucom_stop_read) {
407			(sc->sc_callback->ucom_stop_read) (sc);
408		}
409		if (sc->sc_callback->ucom_stop_write) {
410			(sc->sc_callback->ucom_stop_write) (sc);
411		}
412		mtx_unlock(sc->sc_mtx);
413	}
414	cv_destroy(&sc->sc_cv);
415}
416
417void
418ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
419{
420    char buf[64];
421    uint8_t iface_index;
422    struct usb_attach_arg *uaa;
423
424    snprintf(buf, sizeof(buf), "ttyname=%s%d ttyports=%d",
425	     UCOM_TTY_PREFIX, ssc->sc_unit, ssc->sc_subunits);
426
427    /* Store the PNP info in the first interface for the dev */
428    uaa = device_get_ivars(dev);
429    iface_index = uaa->info.bIfaceIndex;
430
431    if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
432	device_printf(dev, "Could not set PNP info\n");
433}
434
435static void
436ucom_queue_command(struct ucom_softc *sc,
437    usb_proc_callback_t *fn, struct termios *pt,
438    struct usb_proc_msg *t0, struct usb_proc_msg *t1)
439{
440	struct ucom_super_softc *ssc = sc->sc_super;
441	struct ucom_param_task *task;
442
443	mtx_assert(sc->sc_mtx, MA_OWNED);
444
445	if (usb_proc_is_gone(&ssc->sc_tq)) {
446		DPRINTF("proc is gone\n");
447		return;         /* nothing to do */
448	}
449	/*
450	 * NOTE: The task cannot get executed before we drop the
451	 * "sc_mtx" mutex. It is safe to update fields in the message
452	 * structure after that the message got queued.
453	 */
454	task = (struct ucom_param_task *)
455	  usb_proc_msignal(&ssc->sc_tq, t0, t1);
456
457	/* Setup callback and softc pointers */
458	task->hdr.pm_callback = fn;
459	task->sc = sc;
460
461	/*
462	 * Make a copy of the termios. This field is only present if
463	 * the "pt" field is not NULL.
464	 */
465	if (pt != NULL)
466		task->termios_copy = *pt;
467
468	/*
469	 * Closing the device should be synchronous.
470	 */
471	if (fn == ucom_cfg_close)
472		usb_proc_mwait(&ssc->sc_tq, t0, t1);
473
474	/*
475	 * In case of multiple configure requests,
476	 * keep track of the last one!
477	 */
478	if (fn == ucom_cfg_start_transfers)
479		sc->sc_last_start_xfer = &task->hdr;
480}
481
482static void
483ucom_shutdown(struct ucom_softc *sc)
484{
485	struct tty *tp = sc->sc_tty;
486
487	mtx_assert(sc->sc_mtx, MA_OWNED);
488
489	DPRINTF("\n");
490
491	/*
492	 * Hang up if necessary:
493	 */
494	if (tp->t_termios.c_cflag & HUPCL) {
495		ucom_modem(tp, 0, SER_DTR);
496	}
497}
498
499/*
500 * Return values:
501 *    0: normal
502 * else: taskqueue is draining or gone
503 */
504uint8_t
505ucom_cfg_is_gone(struct ucom_softc *sc)
506{
507	struct ucom_super_softc *ssc = sc->sc_super;
508
509	return (usb_proc_is_gone(&ssc->sc_tq));
510}
511
512static void
513ucom_cfg_start_transfers(struct usb_proc_msg *_task)
514{
515	struct ucom_cfg_task *task =
516	    (struct ucom_cfg_task *)_task;
517	struct ucom_softc *sc = task->sc;
518
519	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
520		return;
521	}
522	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
523		/* TTY device closed */
524		return;
525	}
526
527	if (_task == sc->sc_last_start_xfer)
528		sc->sc_flag |= UCOM_FLAG_GP_DATA;
529
530	if (sc->sc_callback->ucom_start_read) {
531		(sc->sc_callback->ucom_start_read) (sc);
532	}
533	if (sc->sc_callback->ucom_start_write) {
534		(sc->sc_callback->ucom_start_write) (sc);
535	}
536}
537
538static void
539ucom_start_transfers(struct ucom_softc *sc)
540{
541	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
542		return;
543	}
544	/*
545	 * Make sure that data transfers are started in both
546	 * directions:
547	 */
548	if (sc->sc_callback->ucom_start_read) {
549		(sc->sc_callback->ucom_start_read) (sc);
550	}
551	if (sc->sc_callback->ucom_start_write) {
552		(sc->sc_callback->ucom_start_write) (sc);
553	}
554}
555
556static void
557ucom_cfg_open(struct usb_proc_msg *_task)
558{
559	struct ucom_cfg_task *task =
560	    (struct ucom_cfg_task *)_task;
561	struct ucom_softc *sc = task->sc;
562
563	DPRINTF("\n");
564
565	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
566
567		/* already opened */
568
569	} else {
570
571		sc->sc_flag |= UCOM_FLAG_LL_READY;
572
573		if (sc->sc_callback->ucom_cfg_open) {
574			(sc->sc_callback->ucom_cfg_open) (sc);
575
576			/* wait a little */
577			usb_pause_mtx(sc->sc_mtx, hz / 10);
578		}
579	}
580}
581
582static int
583ucom_open(struct tty *tp)
584{
585	struct ucom_softc *sc = tty_softc(tp);
586	int error;
587
588	mtx_assert(sc->sc_mtx, MA_OWNED);
589
590	if (sc->sc_flag & UCOM_FLAG_GONE) {
591		return (ENXIO);
592	}
593	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
594		/* already opened */
595		return (0);
596	}
597	DPRINTF("tp = %p\n", tp);
598
599	if (sc->sc_callback->ucom_pre_open) {
600		/*
601		 * give the lower layer a chance to disallow TTY open, for
602		 * example if the device is not present:
603		 */
604		error = (sc->sc_callback->ucom_pre_open) (sc);
605		if (error) {
606			return (error);
607		}
608	}
609	sc->sc_flag |= UCOM_FLAG_HL_READY;
610
611	/* Disable transfers */
612	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
613
614	sc->sc_lsr = 0;
615	sc->sc_msr = 0;
616	sc->sc_mcr = 0;
617
618	/* reset programmed line state */
619	sc->sc_pls_curr = 0;
620	sc->sc_pls_set = 0;
621	sc->sc_pls_clr = 0;
622
623	ucom_queue_command(sc, ucom_cfg_open, NULL,
624	    &sc->sc_open_task[0].hdr,
625	    &sc->sc_open_task[1].hdr);
626
627	/* Queue transfer enable command last */
628	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
629	    &sc->sc_start_task[0].hdr,
630	    &sc->sc_start_task[1].hdr);
631
632	ucom_modem(tp, SER_DTR | SER_RTS, 0);
633
634	ucom_ring(sc, 0);
635
636	ucom_break(sc, 0);
637
638	ucom_status_change(sc);
639
640	return (0);
641}
642
643static void
644ucom_cfg_close(struct usb_proc_msg *_task)
645{
646	struct ucom_cfg_task *task =
647	    (struct ucom_cfg_task *)_task;
648	struct ucom_softc *sc = task->sc;
649
650	DPRINTF("\n");
651
652	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
653		sc->sc_flag &= ~UCOM_FLAG_LL_READY;
654		if (sc->sc_callback->ucom_cfg_close)
655			(sc->sc_callback->ucom_cfg_close) (sc);
656	} else {
657		/* already closed */
658	}
659}
660
661static void
662ucom_close(struct tty *tp)
663{
664	struct ucom_softc *sc = tty_softc(tp);
665
666	mtx_assert(sc->sc_mtx, MA_OWNED);
667
668	DPRINTF("tp=%p\n", tp);
669
670	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
671		DPRINTF("tp=%p already closed\n", tp);
672		return;
673	}
674	ucom_shutdown(sc);
675
676	ucom_queue_command(sc, ucom_cfg_close, NULL,
677	    &sc->sc_close_task[0].hdr,
678	    &sc->sc_close_task[1].hdr);
679
680	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
681
682	if (sc->sc_callback->ucom_stop_read) {
683		(sc->sc_callback->ucom_stop_read) (sc);
684	}
685}
686
687static int
688ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
689{
690	struct ucom_softc *sc = tty_softc(tp);
691	int error;
692
693	mtx_assert(sc->sc_mtx, MA_OWNED);
694
695	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
696		return (EIO);
697	}
698	DPRINTF("cmd = 0x%08lx\n", cmd);
699
700	switch (cmd) {
701#if 0
702	case TIOCSRING:
703		ucom_ring(sc, 1);
704		error = 0;
705		break;
706	case TIOCCRING:
707		ucom_ring(sc, 0);
708		error = 0;
709		break;
710#endif
711	case TIOCSBRK:
712		ucom_break(sc, 1);
713		error = 0;
714		break;
715	case TIOCCBRK:
716		ucom_break(sc, 0);
717		error = 0;
718		break;
719	default:
720		if (sc->sc_callback->ucom_ioctl) {
721			error = (sc->sc_callback->ucom_ioctl)
722			    (sc, cmd, data, 0, td);
723		} else {
724			error = ENOIOCTL;
725		}
726		break;
727	}
728	return (error);
729}
730
731static int
732ucom_modem(struct tty *tp, int sigon, int sigoff)
733{
734	struct ucom_softc *sc = tty_softc(tp);
735	uint8_t onoff;
736
737	mtx_assert(sc->sc_mtx, MA_OWNED);
738
739	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
740		return (0);
741	}
742	if ((sigon == 0) && (sigoff == 0)) {
743
744		if (sc->sc_mcr & SER_DTR) {
745			sigon |= SER_DTR;
746		}
747		if (sc->sc_mcr & SER_RTS) {
748			sigon |= SER_RTS;
749		}
750		if (sc->sc_msr & SER_CTS) {
751			sigon |= SER_CTS;
752		}
753		if (sc->sc_msr & SER_DCD) {
754			sigon |= SER_DCD;
755		}
756		if (sc->sc_msr & SER_DSR) {
757			sigon |= SER_DSR;
758		}
759		if (sc->sc_msr & SER_RI) {
760			sigon |= SER_RI;
761		}
762		return (sigon);
763	}
764	if (sigon & SER_DTR) {
765		sc->sc_mcr |= SER_DTR;
766	}
767	if (sigoff & SER_DTR) {
768		sc->sc_mcr &= ~SER_DTR;
769	}
770	if (sigon & SER_RTS) {
771		sc->sc_mcr |= SER_RTS;
772	}
773	if (sigoff & SER_RTS) {
774		sc->sc_mcr &= ~SER_RTS;
775	}
776	onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
777	ucom_dtr(sc, onoff);
778
779	onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
780	ucom_rts(sc, onoff);
781
782	return (0);
783}
784
785static void
786ucom_cfg_line_state(struct usb_proc_msg *_task)
787{
788	struct ucom_cfg_task *task =
789	    (struct ucom_cfg_task *)_task;
790	struct ucom_softc *sc = task->sc;
791	uint8_t notch_bits;
792	uint8_t any_bits;
793	uint8_t prev_value;
794	uint8_t last_value;
795	uint8_t mask;
796
797	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
798		return;
799	}
800
801	mask = 0;
802	/* compute callback mask */
803	if (sc->sc_callback->ucom_cfg_set_dtr)
804		mask |= UCOM_LS_DTR;
805	if (sc->sc_callback->ucom_cfg_set_rts)
806		mask |= UCOM_LS_RTS;
807	if (sc->sc_callback->ucom_cfg_set_break)
808		mask |= UCOM_LS_BREAK;
809	if (sc->sc_callback->ucom_cfg_set_ring)
810		mask |= UCOM_LS_RING;
811
812	/* compute the bits we are to program */
813	notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
814	any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
815	prev_value = sc->sc_pls_curr ^ notch_bits;
816	last_value = sc->sc_pls_curr;
817
818	/* reset programmed line state */
819	sc->sc_pls_curr = 0;
820	sc->sc_pls_set = 0;
821	sc->sc_pls_clr = 0;
822
823	/* ensure that we don't loose any levels */
824	if (notch_bits & UCOM_LS_DTR)
825		sc->sc_callback->ucom_cfg_set_dtr(sc,
826		    (prev_value & UCOM_LS_DTR) ? 1 : 0);
827	if (notch_bits & UCOM_LS_RTS)
828		sc->sc_callback->ucom_cfg_set_rts(sc,
829		    (prev_value & UCOM_LS_RTS) ? 1 : 0);
830	if (notch_bits & UCOM_LS_BREAK)
831		sc->sc_callback->ucom_cfg_set_break(sc,
832		    (prev_value & UCOM_LS_BREAK) ? 1 : 0);
833	if (notch_bits & UCOM_LS_RING)
834		sc->sc_callback->ucom_cfg_set_ring(sc,
835		    (prev_value & UCOM_LS_RING) ? 1 : 0);
836
837	/* set last value */
838	if (any_bits & UCOM_LS_DTR)
839		sc->sc_callback->ucom_cfg_set_dtr(sc,
840		    (last_value & UCOM_LS_DTR) ? 1 : 0);
841	if (any_bits & UCOM_LS_RTS)
842		sc->sc_callback->ucom_cfg_set_rts(sc,
843		    (last_value & UCOM_LS_RTS) ? 1 : 0);
844	if (any_bits & UCOM_LS_BREAK)
845		sc->sc_callback->ucom_cfg_set_break(sc,
846		    (last_value & UCOM_LS_BREAK) ? 1 : 0);
847	if (any_bits & UCOM_LS_RING)
848		sc->sc_callback->ucom_cfg_set_ring(sc,
849		    (last_value & UCOM_LS_RING) ? 1 : 0);
850}
851
852static void
853ucom_line_state(struct ucom_softc *sc,
854    uint8_t set_bits, uint8_t clear_bits)
855{
856	mtx_assert(sc->sc_mtx, MA_OWNED);
857
858	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
859		return;
860	}
861
862	DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
863
864	/* update current programmed line state */
865	sc->sc_pls_curr |= set_bits;
866	sc->sc_pls_curr &= ~clear_bits;
867	sc->sc_pls_set |= set_bits;
868	sc->sc_pls_clr |= clear_bits;
869
870	/* defer driver programming */
871	ucom_queue_command(sc, ucom_cfg_line_state, NULL,
872	    &sc->sc_line_state_task[0].hdr,
873	    &sc->sc_line_state_task[1].hdr);
874}
875
876static void
877ucom_ring(struct ucom_softc *sc, uint8_t onoff)
878{
879	DPRINTF("onoff = %d\n", onoff);
880
881	if (onoff)
882		ucom_line_state(sc, UCOM_LS_RING, 0);
883	else
884		ucom_line_state(sc, 0, UCOM_LS_RING);
885}
886
887static void
888ucom_break(struct ucom_softc *sc, uint8_t onoff)
889{
890	DPRINTF("onoff = %d\n", onoff);
891
892	if (onoff)
893		ucom_line_state(sc, UCOM_LS_BREAK, 0);
894	else
895		ucom_line_state(sc, 0, UCOM_LS_BREAK);
896}
897
898static void
899ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
900{
901	DPRINTF("onoff = %d\n", onoff);
902
903	if (onoff)
904		ucom_line_state(sc, UCOM_LS_DTR, 0);
905	else
906		ucom_line_state(sc, 0, UCOM_LS_DTR);
907}
908
909static void
910ucom_rts(struct ucom_softc *sc, uint8_t onoff)
911{
912	DPRINTF("onoff = %d\n", onoff);
913
914	if (onoff)
915		ucom_line_state(sc, UCOM_LS_RTS, 0);
916	else
917		ucom_line_state(sc, 0, UCOM_LS_RTS);
918}
919
920static void
921ucom_cfg_status_change(struct usb_proc_msg *_task)
922{
923	struct ucom_cfg_task *task =
924	    (struct ucom_cfg_task *)_task;
925	struct ucom_softc *sc = task->sc;
926	struct tty *tp;
927	uint8_t new_msr;
928	uint8_t new_lsr;
929	uint8_t onoff;
930	uint8_t lsr_delta;
931
932	tp = sc->sc_tty;
933
934	mtx_assert(sc->sc_mtx, MA_OWNED);
935
936	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
937		return;
938	}
939	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
940		return;
941	}
942	/* get status */
943
944	new_msr = 0;
945	new_lsr = 0;
946
947	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
948
949	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
950		/* TTY device closed */
951		return;
952	}
953	onoff = ((sc->sc_msr ^ new_msr) & SER_DCD);
954	lsr_delta = (sc->sc_lsr ^ new_lsr);
955
956	sc->sc_msr = new_msr;
957	sc->sc_lsr = new_lsr;
958
959	if (onoff) {
960
961		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
962
963		DPRINTF("DCD changed to %d\n", onoff);
964
965		ttydisc_modem(tp, onoff);
966	}
967
968	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
969
970		DPRINTF("BREAK detected\n");
971
972		ttydisc_rint(tp, 0, TRE_BREAK);
973		ttydisc_rint_done(tp);
974	}
975
976	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
977
978		DPRINTF("Frame error detected\n");
979
980		ttydisc_rint(tp, 0, TRE_FRAMING);
981		ttydisc_rint_done(tp);
982	}
983
984	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
985
986		DPRINTF("Parity error detected\n");
987
988		ttydisc_rint(tp, 0, TRE_PARITY);
989		ttydisc_rint_done(tp);
990	}
991}
992
993void
994ucom_status_change(struct ucom_softc *sc)
995{
996	mtx_assert(sc->sc_mtx, MA_OWNED);
997
998	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
999		return;		/* not supported */
1000
1001	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1002		return;
1003	}
1004	DPRINTF("\n");
1005
1006	ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1007	    &sc->sc_status_task[0].hdr,
1008	    &sc->sc_status_task[1].hdr);
1009}
1010
1011static void
1012ucom_cfg_param(struct usb_proc_msg *_task)
1013{
1014	struct ucom_param_task *task =
1015	    (struct ucom_param_task *)_task;
1016	struct ucom_softc *sc = task->sc;
1017
1018	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1019		return;
1020	}
1021	if (sc->sc_callback->ucom_cfg_param == NULL) {
1022		return;
1023	}
1024
1025	(sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1026
1027	/* wait a little */
1028	usb_pause_mtx(sc->sc_mtx, hz / 10);
1029}
1030
1031static int
1032ucom_param(struct tty *tp, struct termios *t)
1033{
1034	struct ucom_softc *sc = tty_softc(tp);
1035	uint8_t opened;
1036	int error;
1037
1038	mtx_assert(sc->sc_mtx, MA_OWNED);
1039
1040	opened = 0;
1041	error = 0;
1042
1043	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1044
1045		/* XXX the TTY layer should call "open()" first! */
1046
1047		error = ucom_open(tp);
1048		if (error) {
1049			goto done;
1050		}
1051		opened = 1;
1052	}
1053	DPRINTF("sc = %p\n", sc);
1054
1055	/* Check requested parameters. */
1056	if (t->c_ospeed < 0) {
1057		DPRINTF("negative ospeed\n");
1058		error = EINVAL;
1059		goto done;
1060	}
1061	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1062		DPRINTF("mismatch ispeed and ospeed\n");
1063		error = EINVAL;
1064		goto done;
1065	}
1066	t->c_ispeed = t->c_ospeed;
1067
1068	if (sc->sc_callback->ucom_pre_param) {
1069		/* Let the lower layer verify the parameters */
1070		error = (sc->sc_callback->ucom_pre_param) (sc, t);
1071		if (error) {
1072			DPRINTF("callback error = %d\n", error);
1073			goto done;
1074		}
1075	}
1076
1077	/* Disable transfers */
1078	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1079
1080	/* Queue baud rate programming command first */
1081	ucom_queue_command(sc, ucom_cfg_param, t,
1082	    &sc->sc_param_task[0].hdr,
1083	    &sc->sc_param_task[1].hdr);
1084
1085	/* Queue transfer enable command last */
1086	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1087	    &sc->sc_start_task[0].hdr,
1088	    &sc->sc_start_task[1].hdr);
1089
1090	if (t->c_cflag & CRTS_IFLOW) {
1091		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1092	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1093		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1094		ucom_modem(tp, SER_RTS, 0);
1095	}
1096done:
1097	if (error) {
1098		if (opened) {
1099			ucom_close(tp);
1100		}
1101	}
1102	return (error);
1103}
1104
1105static void
1106ucom_outwakeup(struct tty *tp)
1107{
1108	struct ucom_softc *sc = tty_softc(tp);
1109
1110	mtx_assert(sc->sc_mtx, MA_OWNED);
1111
1112	DPRINTF("sc = %p\n", sc);
1113
1114	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1115		/* The higher layer is not ready */
1116		return;
1117	}
1118	ucom_start_transfers(sc);
1119}
1120
1121/*------------------------------------------------------------------------*
1122 *	ucom_get_data
1123 *
1124 * Return values:
1125 * 0: No data is available.
1126 * Else: Data is available.
1127 *------------------------------------------------------------------------*/
1128uint8_t
1129ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1130    uint32_t offset, uint32_t len, uint32_t *actlen)
1131{
1132	struct usb_page_search res;
1133	struct tty *tp = sc->sc_tty;
1134	uint32_t cnt;
1135	uint32_t offset_orig;
1136
1137	mtx_assert(sc->sc_mtx, MA_OWNED);
1138
1139	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1140		unsigned int temp;
1141
1142		/* get total TX length */
1143
1144		temp = ucom_cons_tx_high - ucom_cons_tx_low;
1145		temp %= UCOM_CONS_BUFSIZE;
1146
1147		/* limit TX length */
1148
1149		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1150			temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1151
1152		if (temp > len)
1153			temp = len;
1154
1155		/* copy in data */
1156
1157		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1158
1159		/* update counters */
1160
1161		ucom_cons_tx_low += temp;
1162		ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1163
1164		/* store actual length */
1165
1166		*actlen = temp;
1167
1168		return (temp ? 1 : 0);
1169	}
1170
1171	if (tty_gone(tp) ||
1172	    !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1173		actlen[0] = 0;
1174		return (0);		/* multiport device polling */
1175	}
1176	offset_orig = offset;
1177
1178	while (len != 0) {
1179
1180		usbd_get_page(pc, offset, &res);
1181
1182		if (res.length > len) {
1183			res.length = len;
1184		}
1185		/* copy data directly into USB buffer */
1186		cnt = ttydisc_getc(tp, res.buffer, res.length);
1187
1188		offset += cnt;
1189		len -= cnt;
1190
1191		if (cnt < res.length) {
1192			/* end of buffer */
1193			break;
1194		}
1195	}
1196
1197	actlen[0] = offset - offset_orig;
1198
1199	DPRINTF("cnt=%d\n", actlen[0]);
1200
1201	if (actlen[0] == 0) {
1202		return (0);
1203	}
1204	return (1);
1205}
1206
1207void
1208ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1209    uint32_t offset, uint32_t len)
1210{
1211	struct usb_page_search res;
1212	struct tty *tp = sc->sc_tty;
1213	char *buf;
1214	uint32_t cnt;
1215
1216	mtx_assert(sc->sc_mtx, MA_OWNED);
1217
1218	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1219		unsigned int temp;
1220
1221		/* get maximum RX length */
1222
1223		temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1224		temp %= UCOM_CONS_BUFSIZE;
1225
1226		/* limit RX length */
1227
1228		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1229			temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1230
1231		if (temp > len)
1232			temp = len;
1233
1234		/* copy out data */
1235
1236		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1237
1238		/* update counters */
1239
1240		ucom_cons_rx_high += temp;
1241		ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1242
1243		return;
1244	}
1245
1246	if (tty_gone(tp))
1247		return;			/* multiport device polling */
1248
1249	if (len == 0)
1250		return;			/* no data */
1251
1252	/* set a flag to prevent recursation ? */
1253
1254	while (len > 0) {
1255
1256		usbd_get_page(pc, offset, &res);
1257
1258		if (res.length > len) {
1259			res.length = len;
1260		}
1261		len -= res.length;
1262		offset += res.length;
1263
1264		/* pass characters to tty layer */
1265
1266		buf = res.buffer;
1267		cnt = res.length;
1268
1269		/* first check if we can pass the buffer directly */
1270
1271		if (ttydisc_can_bypass(tp)) {
1272			if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1273				DPRINTF("tp=%p, data lost\n", tp);
1274			}
1275			continue;
1276		}
1277		/* need to loop */
1278
1279		for (cnt = 0; cnt != res.length; cnt++) {
1280			if (ttydisc_rint(tp, buf[cnt], 0) == -1) {
1281				/* XXX what should we do? */
1282
1283				DPRINTF("tp=%p, lost %d "
1284				    "chars\n", tp, res.length - cnt);
1285				break;
1286			}
1287		}
1288	}
1289	ttydisc_rint_done(tp);
1290}
1291
1292static void
1293ucom_free(void *xsc)
1294{
1295	struct ucom_softc *sc = xsc;
1296
1297	mtx_lock(sc->sc_mtx);
1298	sc->sc_ttyfreed = 1;
1299	cv_signal(&sc->sc_cv);
1300	mtx_unlock(sc->sc_mtx);
1301}
1302
1303static cn_probe_t ucom_cnprobe;
1304static cn_init_t ucom_cninit;
1305static cn_term_t ucom_cnterm;
1306static cn_getc_t ucom_cngetc;
1307static cn_putc_t ucom_cnputc;
1308
1309CONSOLE_DRIVER(ucom);
1310
1311static void
1312ucom_cnprobe(struct consdev  *cp)
1313{
1314	if (ucom_cons_unit != -1)
1315		cp->cn_pri = CN_NORMAL;
1316	else
1317		cp->cn_pri = CN_DEAD;
1318
1319	strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
1320}
1321
1322static void
1323ucom_cninit(struct consdev  *cp)
1324{
1325}
1326
1327static void
1328ucom_cnterm(struct consdev  *cp)
1329{
1330}
1331
1332static int
1333ucom_cngetc(struct consdev *cd)
1334{
1335	struct ucom_softc *sc = ucom_cons_softc;
1336	int c;
1337
1338	if (sc == NULL)
1339		return (-1);
1340
1341	mtx_lock(sc->sc_mtx);
1342
1343	if (ucom_cons_rx_low != ucom_cons_rx_high) {
1344		c = ucom_cons_rx_buf[ucom_cons_rx_low];
1345		ucom_cons_rx_low ++;
1346		ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1347	} else {
1348		c = -1;
1349	}
1350
1351	/* start USB transfers */
1352	ucom_outwakeup(sc->sc_tty);
1353
1354	mtx_unlock(sc->sc_mtx);
1355
1356	/* poll if necessary */
1357	if (kdb_active && sc->sc_callback->ucom_poll)
1358		(sc->sc_callback->ucom_poll) (sc);
1359
1360	return (c);
1361}
1362
1363static void
1364ucom_cnputc(struct consdev *cd, int c)
1365{
1366	struct ucom_softc *sc = ucom_cons_softc;
1367	unsigned int temp;
1368
1369	if (sc == NULL)
1370		return;
1371
1372 repeat:
1373
1374	mtx_lock(sc->sc_mtx);
1375
1376	/* compute maximum TX length */
1377
1378	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1379	temp %= UCOM_CONS_BUFSIZE;
1380
1381	if (temp) {
1382		ucom_cons_tx_buf[ucom_cons_tx_high] = c;
1383		ucom_cons_tx_high ++;
1384		ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1385	}
1386
1387	/* start USB transfers */
1388	ucom_outwakeup(sc->sc_tty);
1389
1390	mtx_unlock(sc->sc_mtx);
1391
1392	/* poll if necessary */
1393	if (kdb_active && sc->sc_callback->ucom_poll) {
1394		(sc->sc_callback->ucom_poll) (sc);
1395		/* simple flow control */
1396		if (temp == 0)
1397			goto repeat;
1398	}
1399}
1400
1401#if defined(GDB)
1402
1403#include <gdb/gdb.h>
1404
1405static gdb_probe_f ucom_gdbprobe;
1406static gdb_init_f ucom_gdbinit;
1407static gdb_term_f ucom_gdbterm;
1408static gdb_getc_f ucom_gdbgetc;
1409static gdb_putc_f ucom_gdbputc;
1410
1411GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
1412
1413static int
1414ucom_gdbprobe(void)
1415{
1416	return ((ucom_cons_softc != NULL) ? 0 : -1);
1417}
1418
1419static void
1420ucom_gdbinit(void)
1421{
1422}
1423
1424static void
1425ucom_gdbterm(void)
1426{
1427}
1428
1429static void
1430ucom_gdbputc(int c)
1431{
1432        ucom_cnputc(NULL, c);
1433}
1434
1435static int
1436ucom_gdbgetc(void)
1437{
1438        return (ucom_cngetc(NULL));
1439}
1440
1441#endif
1442