• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2001-2003, 2005, 2008
7  *	Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
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  *
50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62 
63 #include <unistd.h>
64 #include <los_queue.h>
65 #ifdef LOSCFG_NET_LWIP_SACK
66 #include <lwip/netif.h>
67 #include <lwip/dhcp.h>
68 #include <lwip/netifapi.h>
69 #endif
70 #include "implementation/global_implementation.h"
71 #include "fs/driver.h"
72 
73 extern int ucom_modem(struct ucom_softc *sc, int sigon, int sigoff);
74 
75 #undef USB_DEBUG_VAR
76 #define	USB_DEBUG_VAR   ucom_debug
77 #ifdef LOSCFG_USB_DEBUG
78 static int ucom_debug = 0;
79 void
serial_debug_func(int level)80 serial_debug_func(int level)
81 {
82 	ucom_debug = level;
83 	PRINTK("The level of usb serial debug is %d\n", level);
84 }
85 DEBUG_MODULE(serial, serial_debug_func);
86 #endif
87 
88 #define	UCOM_CONS_BUFSIZE 1024
89 
90 static uint8_t *ucom_cons_rx_buf;
91 static uint8_t *ucom_cons_tx_buf;
92 
93 static unsigned int ucom_cons_rx_low = 0;
94 static unsigned int ucom_cons_rx_high = 0;
95 
96 static unsigned int ucom_cons_tx_low = 0;
97 static unsigned int ucom_cons_tx_high = 0;
98 
99 static struct ucom_softc *ucom_cons_softc = NULL;
100 
101 static int tx_worked = 0;
102 
103 static usb_proc_callback_t ucom_cfg_start_transfers;
104 static usb_proc_callback_t ucom_cfg_open;
105 static usb_proc_callback_t ucom_cfg_close;
106 static usb_proc_callback_t ucom_cfg_line_state;
107 static usb_proc_callback_t ucom_cfg_status_change;
108 
109 static int tty_fd = -1;
110 
111 static void ucom_unit_free(int);
112 static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
113 static void ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
114 static void ucom_queue_command(struct ucom_softc *,
115 		    usb_proc_callback_t *, struct termios *pt,
116 		    struct usb_proc_msg *t0, struct usb_proc_msg *t1);
117 static void ucom_shutdown(struct ucom_softc *);
118 static void ucom_ring(struct ucom_softc *, uint8_t);
119 static void ucom_break(struct ucom_softc *, uint8_t);
120 static void ucom_dtr(struct ucom_softc *, uint8_t);
121 static void ucom_rts(struct ucom_softc *, uint8_t);
122 static void ucom_close(struct ucom_softc *sc);
123 
124 static UINT32 u3g_tx_init(VOID);
125 static UINT32 u3g_tx_deinit(VOID);
126 static void ucom_tx_task(void);
127 
128 static int tty_usb_open(struct file *filep);
129 static int tty_usb_close(struct file *filep);
130 static ssize_t tty_usb_read(struct file *filep, char *buffer, size_t buflen);
131 static ssize_t tty_usb_write(struct file *filep, const char *buffer, size_t buflen);
132 
133 static const struct file_operations_vfs tty_usb_fops =
134 {
135 	tty_usb_open,	/* open */
136 	tty_usb_close,	/* close */
137 	tty_usb_read,	/* read */
138 	tty_usb_write,	/* write */
139 	NULL,			/* seek */
140 	NULL,			/* ioctl */
141 	NULL,			/* mmap */
142 #ifndef CONFIG_DISABLE_POLL
143 	NULL,			/* poll */
144 #endif
145 	NULL			/* unlink */
146 };
147 
148 #define	UCOM_UNIT_MAX		128	/* maximum number of units */
149 #define	UCOM_TTY_PREFIX		"U"
150 
151 static struct mtx ucom_mtx;
152 static int ucom_close_refs;
153 
154 /*
155  * Mark the unit number as not in use.
156  */
157 static void
ucom_unit_free(int unit)158 ucom_unit_free(int unit)
159 {
160 	return;
161 }
162 
163 /*
164  * Setup a group of one or more serial ports.
165  *
166  * The mutex pointed to by "mtx" is applied before all
167  * callbacks are called back. Also "mtx" must be applied
168  * before calling into the ucom-layer!
169  */
170 int
ucom_attach(struct ucom_super_softc * ssc,struct ucom_softc * sc,int subunits,void * parent,const struct ucom_callback * callback,struct mtx * umtx)171 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
172     int subunits, void *parent,
173     const struct ucom_callback *callback, struct mtx *umtx)
174 {
175 	int subunit;
176 	int error;
177 
178 	DPRINTFN(0, "\n");
179 
180 	if ((sc == NULL) ||
181 	    (subunits <= 0) ||
182 	    (callback == NULL) ||
183 	    (umtx == NULL)) {
184 		return (EINVAL);
185 	}
186 
187 	/* allocate a uniq unit number */
188 	ssc->sc_unit = 0;
189 	if (ssc->sc_unit == -1)
190 		return (ENOMEM);
191 
192 	/* generate TTY name string */
193 	(void)snprintf_s(ssc->sc_ttyname, sizeof(ssc->sc_ttyname), sizeof(ssc->sc_ttyname) - 1,
194 	    UCOM_TTY_PREFIX "%d", ssc->sc_unit);
195 
196 	/* create USB request handling process */
197 	error = usb_proc_create(&ssc->sc_tq, umtx, "ucom", USB_PRI_MED);
198 	if (error) {
199 		ucom_unit_free(ssc->sc_unit);
200 		return (error);
201 	}
202 	ssc->sc_subunits = subunits;
203 	ssc->sc_flag = UCOM_FLAG_ATTACHED |
204 	    UCOM_FLAG_FREE_UNIT;
205 
206 	if (callback->ucom_free == NULL)
207 		ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
208 
209 	/* increment reference count */
210 	ucom_ref(ssc);
211 
212 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
213 		sc[subunit].sc_subunit = subunit;
214 		sc[subunit].sc_super = ssc;
215 		sc[subunit].sc_mtx = umtx;
216 		sc[subunit].sc_parent = parent;
217 		sc[subunit].sc_callback = callback;
218 
219 		error = ucom_attach_tty(ssc, &sc[subunit]);
220 		if (error) {
221 			ucom_detach(ssc, &sc[0]);
222 			return (error);
223 		}
224 		/* increment reference count */
225 		ucom_ref(ssc);
226 
227 		/* set subunit attached */
228 		sc[subunit].sc_flag = UCOM_FLAG_ATTACHED;
229 	}
230 
231 	(void)u3g_tx_init();
232 	ucom_cons_rx_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(UCOM_CONS_BUFSIZE));
233 	ucom_cons_tx_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(UCOM_CONS_BUFSIZE));
234 
235 	return (0);
236 }
237 
238 /*
239  * The following function will do nothing if the structure pointed to
240  * by "ssc" and "sc" is zero or has already been detached.
241  */
242 void
ucom_detach(struct ucom_super_softc * ssc,struct ucom_softc * sc)243 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
244 {
245 	int subunit;
246 
247 	if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
248 		return;		/* not initialized */
249 	usb_proc_drain(&ssc->sc_tq);
250 
251 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
252 		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
253 			ucom_detach_tty(ssc, &sc[subunit]);
254 
255 			/* avoid duplicate detach */
256 			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
257 		}
258 	}
259 
260 	tty_fd = -1;
261 
262 	(void)u3g_tx_deinit();
263 
264 	usb_proc_free(&ssc->sc_tq);
265 
266 	free(ucom_cons_rx_buf);
267 	free(ucom_cons_tx_buf);
268 	ucom_cons_rx_buf = NULL;
269 	ucom_cons_tx_buf = NULL;
270 
271 	(void)ucom_unref(ssc);
272 
273 	if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
274 		ucom_drain(ssc);
275 
276 	/* make sure we don't detach twice */
277 	ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
278 
279 	ucom_cons_softc = NULL;
280 }
281 
282 void
ucom_drain(struct ucom_super_softc * ssc)283 ucom_drain(struct ucom_super_softc *ssc)
284 {
285 	mtx_lock(&ucom_mtx);
286 	while (ssc->sc_refs > 0) {
287 		PRINTK("ucom: Waiting for a TTY device to close.\n");
288 		usb_pause_mtx(&ucom_mtx, hz);
289 	}
290 	mtx_unlock(&ucom_mtx);
291 }
292 
293 void
ucom_drain_all(void * arg)294 ucom_drain_all(void *arg)
295 {
296 	mtx_lock(&ucom_mtx);
297 	while (ucom_close_refs > 0) {
298 		PRINTK("ucom: Waiting for all detached TTY "
299 		    "devices to have open fds closed.\n");
300 		usb_pause_mtx(&ucom_mtx, hz);
301 	}
302 	mtx_unlock(&ucom_mtx);
303 }
304 
305 static int
ucom_attach_tty(struct ucom_super_softc * ssc,struct ucom_softc * sc)306 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
307 {
308 	int ret;
309 
310 	ret = snprintf_s(sc->sc_name, TTY_NAME_LEN, TTY_NAME_LEN - 1, "/dev/ttyUSB%d", sc->sc_subunit);
311 	if (ret < 0) {
312 		usb_err("snprintf_s failed\n");
313 		return (-1);
314 	}
315 	(void)register_driver(sc->sc_name, &tty_usb_fops, 0666, sc);
316 	DPRINTF("unit %d subunit %d is console",
317 	    ssc->sc_unit, sc->sc_subunit);
318 
319 	if (ucom_cons_softc == NULL) {
320 		ucom_cons_softc = sc;
321 
322 		UCOM_MTX_LOCK(ucom_cons_softc);
323 		ucom_cons_rx_low = 0;
324 		ucom_cons_rx_high = 0;
325 		ucom_cons_tx_low = 0;
326 		ucom_cons_tx_high = 0;
327 		UCOM_MTX_UNLOCK(ucom_cons_softc);
328 	}
329 
330 	return (0);
331 }
332 
333 static void
ucom_detach_tty(struct ucom_super_softc * ssc,struct ucom_softc * sc)334 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
335 {
336 	/* the config thread has been stopped when we get here */
337 
338 	UCOM_MTX_LOCK(sc);
339 	sc->sc_flag |= UCOM_FLAG_GONE;
340 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
341 	ucom_close(sc);	/* close, if any */
342 	UCOM_MTX_UNLOCK(sc);
343 
344 	(void)unregister_driver(sc->sc_name);
345 
346 	UCOM_MTX_LOCK(sc);
347 	/*
348 	 * make sure that read and write transfers are stopped
349 	 */
350 	if (sc->sc_callback->ucom_stop_read)
351 		(sc->sc_callback->ucom_stop_read) (sc);
352 	if (sc->sc_callback->ucom_stop_write)
353 		(sc->sc_callback->ucom_stop_write) (sc);
354 	UCOM_MTX_UNLOCK(sc);
355 }
356 
357 void
ucom_set_pnpinfo_usb(struct ucom_super_softc * ssc,device_t dev)358 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
359 {
360 	char buf[64];
361 	uint8_t iface_index;
362 	struct usb_attach_arg *uaa;
363 
364 	(void)snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "ttyname=" UCOM_TTY_PREFIX
365 	    "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
366 
367 	/* Store the PNP info in the first interface for the device */
368 	uaa = (struct usb_attach_arg *)device_get_ivars(dev);
369 	iface_index = uaa->info.bIfaceIndex;
370 
371 	if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
372 		device_printf(dev, "Could not set PNP info\n");
373 
374 	/*
375 	 * The following information is also replicated in the PNP-info
376 	 * string which is registered above:
377 	 */
378 
379 }
380 
381 static void
ucom_queue_command(struct ucom_softc * sc,usb_proc_callback_t * fn,struct termios * pt,struct usb_proc_msg * t0,struct usb_proc_msg * t1)382 ucom_queue_command(struct ucom_softc *sc,
383     usb_proc_callback_t *fn, struct termios *pt,
384     struct usb_proc_msg *t0, struct usb_proc_msg *t1)
385 {
386 	struct ucom_super_softc *ssc = sc->sc_super;
387 	struct ucom_param_task *task;
388 
389 	UCOM_MTX_ASSERT(sc, MA_OWNED);
390 
391 	if (usb_proc_is_gone(&ssc->sc_tq)) {
392 		DPRINTF("proc is gone\n");
393 		return;		/* nothing to do */
394 	}
395 	/*
396 	 * NOTE: The task cannot get executed before we drop the
397 	 * "sc_mtx" mutex. It is safe to update fields in the message
398 	 * structure after that the message got queued.
399 	 */
400 	task = (struct ucom_param_task *)
401 	    usb_proc_msignal(&ssc->sc_tq, t0, t1);
402 
403 	/* Setup callback and softc pointers */
404 	task->hdr.pm_callback = fn;
405 	task->sc = sc;
406 
407 	/*
408 	 * Make a copy of the termios. This field is only present if
409 	 * the "pt" field is not NULL.
410 	 */
411 	if (pt != NULL)
412 		task->termios_copy = *pt;
413 
414 	/*
415 	 * Closing the device should be synchronous.
416 	 */
417 	if (fn == ucom_cfg_close)
418 		usb_proc_mwait(&ssc->sc_tq, t0, t1);
419 
420 	/*
421 	 * In case of multiple configure requests,
422 	 * keep track of the last one!
423 	 */
424 	if (fn == ucom_cfg_start_transfers)
425 		sc->sc_last_start_xfer = &task->hdr;
426 }
427 
428 static void
ucom_shutdown(struct ucom_softc * sc)429 ucom_shutdown(struct ucom_softc *sc)
430 {
431 }
432 
433 /*
434  * Return values:
435  *	0: normal
436  * else: taskqueue is draining or gone
437  */
438 uint8_t
ucom_cfg_is_gone(struct ucom_softc * sc)439 ucom_cfg_is_gone(struct ucom_softc *sc)
440 {
441 	struct ucom_super_softc *ssc = sc->sc_super;
442 
443 	return (usb_proc_is_gone(&ssc->sc_tq));
444 }
445 
446 static void
ucom_cfg_start_transfers(struct usb_proc_msg * _task)447 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
448 {
449 	struct ucom_cfg_task *task =
450 	    (struct ucom_cfg_task *)_task;
451 	struct ucom_softc *sc = task->sc;
452 
453 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
454 		return;
455 	}
456 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
457 		/* TTY device closed */
458 		return;
459 	}
460 
461 	if (_task == sc->sc_last_start_xfer)
462 		sc->sc_flag |= UCOM_FLAG_GP_DATA;
463 
464 	if (sc->sc_callback->ucom_start_read) {
465 		(sc->sc_callback->ucom_start_read) (sc);
466 	}
467 	if (sc->sc_callback->ucom_start_write) {
468 		(sc->sc_callback->ucom_start_write) (sc);
469 	}
470 }
471 
472 void
ucom_start_transfers(struct ucom_softc * sc)473 ucom_start_transfers(struct ucom_softc *sc)
474 {
475 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
476 		return;
477 	}
478 	/*
479 	 * Make sure that data transfers are started in both
480 	 * directions:
481 	 */
482 	if (sc->sc_callback->ucom_start_read) {
483 		(sc->sc_callback->ucom_start_read) (sc);
484 	}
485 	if (sc->sc_callback->ucom_start_write) {
486 		(sc->sc_callback->ucom_start_write) (sc);
487 	}
488 }
489 
490 static void
ucom_cfg_open(struct usb_proc_msg * _task)491 ucom_cfg_open(struct usb_proc_msg *_task)
492 {
493 	struct ucom_cfg_task *task =
494 	    (struct ucom_cfg_task *)_task;
495 	struct ucom_softc *sc = task->sc;
496 
497 	DPRINTF("\n");
498 
499 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
500 		/* already opened */
501 
502 	} else {
503 		sc->sc_flag |= UCOM_FLAG_LL_READY;
504 
505 		if (sc->sc_callback->ucom_cfg_open) {
506 			(sc->sc_callback->ucom_cfg_open) (sc);
507 
508 			/* wait a little */
509 			usb_pause_mtx(sc->sc_mtx, hz / 10);
510 		}
511 	}
512 }
513 
514 int
ucom_open(struct ucom_softc * sc)515 ucom_open(struct ucom_softc *sc)
516 {
517 	int error;
518 
519 	UCOM_MTX_ASSERT(sc, MA_OWNED);
520 
521 	if (sc->sc_flag & UCOM_FLAG_GONE) {
522 		return (ENXIO);
523 	}
524 	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
525 		/* already opened */
526 		return (0);
527 	}
528 	DPRINTF("sc = %p\n", sc);
529 
530 	if (sc->sc_callback->ucom_pre_open) {
531 		/*
532 		 * give the lower layer a chance to disallow TTY open, for
533 		 * example if the device is not present:
534 		 */
535 		error = (sc->sc_callback->ucom_pre_open) (sc);
536 		if (error) {
537 			PRINT_ERR("error %d\n",error);
538 			return (error);
539 		}
540 	}
541 	sc->sc_flag |= UCOM_FLAG_HL_READY;
542 
543 	/* Disable transfers */
544 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
545 
546 	sc->sc_lsr = 0;
547 	sc->sc_msr = 0;
548 	sc->sc_mcr = 0;
549 
550 	/* reset programmed line state */
551 	sc->sc_pls_curr = 0;
552 	sc->sc_pls_set = 0;
553 	sc->sc_pls_clr = 0;
554 
555 	/* reset jitter buffer */
556 	sc->sc_jitterbuf_in = 0;
557 	sc->sc_jitterbuf_out = 0;
558 
559 	ucom_queue_command(sc, ucom_cfg_open, NULL,
560 	    &sc->sc_open_task[0].hdr,
561 	    &sc->sc_open_task[1].hdr);
562 
563 	/* Queue transfer enable command last */
564 	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
565 	    &sc->sc_start_task[0].hdr,
566 	    &sc->sc_start_task[1].hdr);
567 
568 	(void)ucom_modem(sc, SER_DTR | SER_RTS, 0);
569 
570 	ucom_ring(sc, 0);
571 
572 	ucom_break(sc, 0);
573 
574 	return (0);
575 }
576 
577 static void
ucom_cfg_close(struct usb_proc_msg * _task)578 ucom_cfg_close(struct usb_proc_msg *_task)
579 {
580 	struct ucom_cfg_task *task =
581 	    (struct ucom_cfg_task *)_task;
582 	struct ucom_softc *sc = task->sc;
583 
584 	DPRINTF("\n");
585 
586 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
587 		sc->sc_flag &= ~UCOM_FLAG_LL_READY;
588 		if (sc->sc_callback->ucom_cfg_close)
589 			(sc->sc_callback->ucom_cfg_close) (sc);
590 	} else {
591 		/* already closed */
592 	}
593 }
594 
595 static void
ucom_close(struct ucom_softc * sc)596 ucom_close(struct ucom_softc *sc)
597 {
598 	UCOM_MTX_ASSERT(sc, MA_OWNED);
599 
600 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
601 		DPRINTF("tp=%p already closed\n", sc);
602 		return;
603 	}
604 	ucom_shutdown(sc);
605 
606 	ucom_queue_command(sc, ucom_cfg_close, NULL,
607 	    &sc->sc_close_task[0].hdr,
608 	    &sc->sc_close_task[1].hdr);
609 
610 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
611 
612 	if (sc->sc_callback->ucom_stop_read) {
613 		(sc->sc_callback->ucom_stop_read) (sc);
614 	}
615 
616 	ucom_cons_rx_low = 0;
617 	ucom_cons_rx_high = 0;
618 
619 	ucom_cons_tx_low = 0;
620 	ucom_cons_tx_high = 0;
621 
622 }
623 
624 int
ucom_modem(struct ucom_softc * sc,int sigon,int sigoff)625 ucom_modem(struct ucom_softc *sc, int sigon, int sigoff)
626 {
627 	uint8_t onoff;
628 
629 	UCOM_MTX_ASSERT(sc, MA_OWNED);
630 
631 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
632 		return (0);
633 	}
634 	if ((sigon == 0) && (sigoff == 0)) {
635 		if (sc->sc_mcr & SER_DTR) {
636 			sigon |= SER_DTR;
637 		}
638 		if (sc->sc_mcr & SER_RTS) {
639 			sigon |= SER_RTS;
640 		}
641 		if (sc->sc_msr & SER_CTS) {
642 			sigon |= SER_CTS;
643 		}
644 		if (sc->sc_msr & SER_DCD) {
645 			sigon |= SER_DCD;
646 		}
647 		if (sc->sc_msr & SER_DSR) {
648 			sigon |= SER_DSR;
649 		}
650 		if (sc->sc_msr & SER_RI) {
651 			sigon |= SER_RI;
652 		}
653 		return (sigon);
654 	}
655 	if (sigon & SER_DTR) {
656 		sc->sc_mcr |= SER_DTR;
657 	}
658 	if (sigoff & SER_DTR) {
659 		sc->sc_mcr &= ~SER_DTR;
660 	}
661 	if (sigon & SER_RTS) {
662 		sc->sc_mcr |= SER_RTS;
663 	}
664 	if (sigoff & SER_RTS) {
665 		sc->sc_mcr &= ~SER_RTS;
666 	}
667 	onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
668 	ucom_dtr(sc, onoff);
669 
670 	onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
671 	ucom_rts(sc, onoff);
672 
673 	return (0);
674 }
675 
676 static void
ucom_cfg_line_state(struct usb_proc_msg * _task)677 ucom_cfg_line_state(struct usb_proc_msg *_task)
678 {
679 	struct ucom_cfg_task *task =
680 	    (struct ucom_cfg_task *)_task;
681 	struct ucom_softc *sc = task->sc;
682 	uint8_t notch_bits;
683 	uint8_t any_bits;
684 	uint8_t prev_value;
685 	uint8_t last_value;
686 	uint8_t mask;
687 
688 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
689 		return;
690 	}
691 
692 	mask = 0;
693 	/* compute callback mask */
694 	if (sc->sc_callback->ucom_cfg_set_dtr)
695 		mask |= UCOM_LS_DTR;
696 	if (sc->sc_callback->ucom_cfg_set_rts)
697 		mask |= UCOM_LS_RTS;
698 	if (sc->sc_callback->ucom_cfg_set_break)
699 		mask |= UCOM_LS_BREAK;
700 	if (sc->sc_callback->ucom_cfg_set_ring)
701 		mask |= UCOM_LS_RING;
702 
703 	/* compute the bits we are to program */
704 	notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
705 	any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
706 	prev_value = sc->sc_pls_curr ^ notch_bits;
707 	last_value = sc->sc_pls_curr;
708 
709 	/* reset programmed line state */
710 	sc->sc_pls_curr = 0;
711 	sc->sc_pls_set = 0;
712 	sc->sc_pls_clr = 0;
713 
714 	/* ensure that we don't lose any levels */
715 	if (notch_bits & UCOM_LS_DTR)
716 		sc->sc_callback->ucom_cfg_set_dtr(sc,
717 		    (prev_value & UCOM_LS_DTR) ? 1 : 0);
718 	if (notch_bits & UCOM_LS_RTS)
719 		sc->sc_callback->ucom_cfg_set_rts(sc,
720 		    (prev_value & UCOM_LS_RTS) ? 1 : 0);
721 	if (notch_bits & UCOM_LS_BREAK)
722 		sc->sc_callback->ucom_cfg_set_break(sc,
723 		    (prev_value & UCOM_LS_BREAK) ? 1 : 0);
724 	if (notch_bits & UCOM_LS_RING)
725 		sc->sc_callback->ucom_cfg_set_ring(sc,
726 		    (prev_value & UCOM_LS_RING) ? 1 : 0);
727 
728 	/* set last value */
729 	if (any_bits & UCOM_LS_DTR)
730 		sc->sc_callback->ucom_cfg_set_dtr(sc,
731 		    (last_value & UCOM_LS_DTR) ? 1 : 0);
732 	if (any_bits & UCOM_LS_RTS)
733 		sc->sc_callback->ucom_cfg_set_rts(sc,
734 		    (last_value & UCOM_LS_RTS) ? 1 : 0);
735 	if (any_bits & UCOM_LS_BREAK)
736 		sc->sc_callback->ucom_cfg_set_break(sc,
737 		    (last_value & UCOM_LS_BREAK) ? 1 : 0);
738 	if (any_bits & UCOM_LS_RING)
739 		sc->sc_callback->ucom_cfg_set_ring(sc,
740 		    (last_value & UCOM_LS_RING) ? 1 : 0);
741 }
742 
743 static void
ucom_line_state(struct ucom_softc * sc,uint8_t set_bits,uint8_t clear_bits)744 ucom_line_state(struct ucom_softc *sc,
745     uint8_t set_bits, uint8_t clear_bits)
746 {
747 	UCOM_MTX_ASSERT(sc, MA_OWNED);
748 
749 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
750 		return;
751 	}
752 
753 	DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
754 
755 	/* update current programmed line state */
756 	sc->sc_pls_curr |= set_bits;
757 	sc->sc_pls_curr &= ~clear_bits;
758 	sc->sc_pls_set |= set_bits;
759 	sc->sc_pls_clr |= clear_bits;
760 
761 	/* defer driver programming */
762 	ucom_queue_command(sc, ucom_cfg_line_state, NULL,
763 	    &sc->sc_line_state_task[0].hdr,
764 	    &sc->sc_line_state_task[1].hdr);
765 }
766 
767 static void
ucom_ring(struct ucom_softc * sc,uint8_t onoff)768 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
769 {
770 	DPRINTF("onoff = %d\n", onoff);
771 
772 	if (onoff)
773 		ucom_line_state(sc, UCOM_LS_RING, 0);
774 	else
775 		ucom_line_state(sc, 0, UCOM_LS_RING);
776 }
777 
778 static void
ucom_break(struct ucom_softc * sc,uint8_t onoff)779 ucom_break(struct ucom_softc *sc, uint8_t onoff)
780 {
781 	DPRINTF("onoff = %d\n", onoff);
782 
783 	if (onoff)
784 		ucom_line_state(sc, UCOM_LS_BREAK, 0);
785 	else
786 		ucom_line_state(sc, 0, UCOM_LS_BREAK);
787 }
788 
789 static void
ucom_dtr(struct ucom_softc * sc,uint8_t onoff)790 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
791 {
792 	DPRINTF("onoff = %d\n", onoff);
793 
794 	if (onoff)
795 		ucom_line_state(sc, UCOM_LS_DTR, 0);
796 	else
797 		ucom_line_state(sc, 0, UCOM_LS_DTR);
798 }
799 
800 static void
ucom_rts(struct ucom_softc * sc,uint8_t onoff)801 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
802 {
803 	DPRINTF("onoff = %d\n", onoff);
804 
805 	if (onoff)
806 		ucom_line_state(sc, UCOM_LS_RTS, 0);
807 	else
808 		ucom_line_state(sc, 0, UCOM_LS_RTS);
809 }
810 
811 static void
ucom_cfg_status_change(struct usb_proc_msg * _task)812 ucom_cfg_status_change(struct usb_proc_msg *_task)
813 {
814 	struct ucom_cfg_task *task =
815 	    (struct ucom_cfg_task *)_task;
816 	struct ucom_softc *sc = task->sc;
817 	uint8_t new_msr;
818 	uint8_t new_lsr;
819 	uint8_t onoff;
820 	uint8_t lsr_delta;
821 
822 	UCOM_MTX_ASSERT(sc, MA_OWNED);
823 
824 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
825 		return;
826 	}
827 	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
828 		return;
829 	}
830 	/* get status */
831 
832 	new_msr = 0;
833 	new_lsr = 0;
834 
835 	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
836 
837 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
838 		/* TTY device closed */
839 		return;
840 	}
841 	onoff = ((sc->sc_msr ^ new_msr) & SER_DCD);
842 	lsr_delta = (sc->sc_lsr ^ new_lsr);
843 
844 	sc->sc_msr = new_msr;
845 	sc->sc_lsr = new_lsr;
846 
847 	if (onoff) {
848 		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
849 		DPRINTF("DCD changed to %d\n", onoff);
850 	}
851 
852 	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
853 		DPRINTF("BREAK detected\n");
854 	}
855 
856 	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
857 		DPRINTF("Frame error detected\n");
858 	}
859 
860 	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
861 		DPRINTF("Parity error detected\n");
862 	}
863 }
864 
865 void
ucom_status_change(struct ucom_softc * sc)866 ucom_status_change(struct ucom_softc *sc)
867 {
868 	UCOM_MTX_ASSERT(sc, MA_OWNED);
869 
870 	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
871 		return;		/* not supported */
872 
873 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
874 		return;
875 	}
876 	DPRINTF("\n");
877 
878 	ucom_queue_command(sc, ucom_cfg_status_change, NULL,
879 	    &sc->sc_status_task[0].hdr,
880 	    &sc->sc_status_task[1].hdr);
881 }
882 
883 static void
ucom_outwakeup(struct ucom_softc * sc)884 ucom_outwakeup(struct ucom_softc *sc)
885 {
886 	UCOM_MTX_ASSERT(sc, MA_OWNED);
887 
888 	DPRINTF("sc = %p\n", sc);
889 
890 	ucom_start_transfers(sc);
891 }
892 
893 /*------------------------------------------------------------------------*
894  *	ucom_get_data
895  *
896  * Return values:
897  * 0: No data is available.
898  * Else: Data is available.
899  *------------------------------------------------------------------------*/
900 uint8_t
ucom_get_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len,uint32_t * actlen)901 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
902     uint32_t offset, uint32_t len, uint32_t *actlen)
903 {
904 	unsigned int temp;
905 	UCOM_MTX_ASSERT(sc, MA_OWNED);
906 
907 	/* get total TX length */
908 	temp = ucom_cons_tx_high - ucom_cons_tx_low;
909 	temp %= UCOM_CONS_BUFSIZE;
910 
911 	if (temp > len)
912 		temp = len;
913 
914 	/* copy in data */
915 	if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low)){
916 		unsigned int fisrt_len = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
917 		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, fisrt_len);
918 		usbd_copy_in(pc, offset+fisrt_len, ucom_cons_tx_buf, temp-fisrt_len);
919 		PRINTK("len1 : %d ; len2 : %d \n", fisrt_len, temp);
920 	}else
921 		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
922 
923 	/* update counters */
924 	ucom_cons_tx_low += temp;
925 	ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
926 
927 	/* store actual length */
928 
929 	*actlen = temp;
930 
931 	return (temp ? 1 : 0);
932 
933 }
934 
935 void
ucom_put_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len)936 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
937     uint32_t offset, uint32_t len)
938 {
939 	unsigned int temp;
940 	UCOM_MTX_ASSERT(sc, MA_OWNED);
941 
942 	/* get maximum RX length */
943 	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
944 	temp %= UCOM_CONS_BUFSIZE;
945 
946 	if (temp > len)
947 		temp = len;
948 
949 	/* limit RX length */
950 	if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high)){
951 		unsigned int first_len = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
952 		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, first_len);
953 		usbd_copy_out(pc, offset+first_len, ucom_cons_rx_buf, temp-first_len);
954 	/* copy out data */
955 	}else
956 		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
957 
958 	/* update counters */
959 	ucom_cons_rx_high += temp;
960 	ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
961 
962 	return;
963 }
964 
965 /*------------------------------------------------------------------------*
966  *	ucom_ref
967  *
968  * This function will increment the super UCOM reference count.
969  *------------------------------------------------------------------------*/
970 void
ucom_ref(struct ucom_super_softc * ssc)971 ucom_ref(struct ucom_super_softc *ssc)
972 {
973 	mtx_lock(&ucom_mtx);
974 	ssc->sc_refs++;
975 	mtx_unlock(&ucom_mtx);
976 }
977 
978 /*------------------------------------------------------------------------*
979  *	ucom_free_unit
980  *
981  * This function will free the super UCOM's allocated unit
982  * number. This function can be called on a zero-initialized
983  * structure. This function can be called multiple times.
984  *------------------------------------------------------------------------*/
985 static void
ucom_free_unit(struct ucom_super_softc * ssc)986 ucom_free_unit(struct ucom_super_softc *ssc)
987 {
988 	if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
989 		return;
990 
991 	ucom_unit_free(ssc->sc_unit);
992 
993 	ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
994 }
995 
996 /*------------------------------------------------------------------------*
997  *	ucom_unref
998  *
999  * This function will decrement the super UCOM reference count.
1000  *
1001  * Return values:
1002  * 0: UCOM structures are still referenced.
1003  * Else: UCOM structures are no longer referenced.
1004  *------------------------------------------------------------------------*/
1005 int
ucom_unref(struct ucom_super_softc * ssc)1006 ucom_unref(struct ucom_super_softc *ssc)
1007 {
1008 	int retval;
1009 
1010 	mtx_lock(&ucom_mtx);
1011 	retval = (ssc->sc_refs < 2);
1012 	ssc->sc_refs--;
1013 	mtx_unlock(&ucom_mtx);
1014 
1015 	if (retval)
1016 		ucom_free_unit(ssc);
1017 
1018 	return (retval);
1019 }
1020 
1021 static void
tx_data_copy_in(struct ucom_softc * sc,const void * tx_data,unsigned int len)1022 tx_data_copy_in(struct ucom_softc *sc, const void *tx_data, unsigned int len)
1023 {
1024 	unsigned int temp;
1025 	int ret;
1026 
1027 	UCOM_MTX_LOCK(sc);
1028 
1029 	if(len > UCOM_CONS_BUFSIZE)
1030 		len = UCOM_CONS_BUFSIZE;
1031 
1032 	/* get maximum TX length */
1033 	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1034 	temp %= UCOM_CONS_BUFSIZE;
1035 
1036 	if (temp >= len)
1037 		temp = len;
1038 
1039 	/* limit RX length */
1040 	if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_high)){
1041 		temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_high);
1042 		/* copy out data */
1043 		ret = usbd_copy_from_user(ucom_cons_tx_buf + ucom_cons_tx_high, temp, tx_data, temp);
1044 		if (ret != EOK) {
1045 			UCOM_MTX_UNLOCK(sc);
1046 			usb_err("memcpy_s failed!, ret:%d\n", ret);
1047 			return;
1048 		}
1049 		ret = usbd_copy_from_user(ucom_cons_tx_buf, UCOM_CONS_BUFSIZE,
1050 			    (const void *)((char *)tx_data + temp), len - temp);
1051 		if (ret != EOK) {
1052 			UCOM_MTX_UNLOCK(sc);
1053 			usb_err("memcpy_s failed!, ret:%d\n", ret);
1054 			return;
1055 		}
1056 	} else {
1057 		ret = usbd_copy_from_user(ucom_cons_tx_buf + ucom_cons_tx_high,
1058 			    UCOM_CONS_BUFSIZE - ucom_cons_tx_high, tx_data, len);
1059 		if (ret != EOK) {
1060 			UCOM_MTX_UNLOCK(sc);
1061 			usb_err("memcpy_s failed!, ret:%d\n", ret);
1062 			return;
1063 		}
1064 	}
1065 
1066 	/* update counters */
1067 	ucom_cons_tx_high += len;
1068 	ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1069 
1070 	UCOM_MTX_UNLOCK(sc);
1071 	return;
1072 }
1073 
1074 static UINT8 m_auc_ucom_handler_pool[sizeof(OS_MEMBOX_S) +
1075 			    ((sizeof(ucom_handler_item_s) + 3) & (~3)) * 8];
1076 static UINT32 m_uw_ucom_handler_queue;
1077 static UINT32 g_u3g_tx_taskid = 0;
1078 static UINT32 g_u3g_rx_taskid = 0;
1079 
1080 static void
ucom_rx_task(void)1081 ucom_rx_task(void)
1082 {
1083 	char buffer[128] = {0};
1084 	int length;
1085 	int i;
1086 
1087 	while (1) {
1088 		if (tty_fd > 0) {
1089 			length = read(tty_fd, buffer, 128);
1090 			if (length > 0) {
1091 				for (i = 0; i < length; i++) {
1092 					printf("%c", *(buffer + i));
1093 				}
1094 				printf("\n");
1095 			}
1096 		}
1097 		LOS_Msleep(50);
1098 	}
1099 }
1100 
1101 static UINT32
u3g_tx_init(VOID)1102 u3g_tx_init(VOID)
1103 {
1104 	TSK_INIT_PARAM_S stappTask;
1105 	UINT32 ret;
1106 
1107 	(void)memset_s(&stappTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
1108 	stappTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ucom_tx_task;
1109 	stappTask.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
1110 	stappTask.pcName =		 "u3g_tx_Task";
1111 	stappTask.usTaskPrio =	 9;
1112 	stappTask.uwResved   =	 LOS_TASK_STATUS_DETACHED;
1113 	ret = LOS_TaskCreate(&g_u3g_tx_taskid, &stappTask);
1114 	if (ret != LOS_OK) {
1115 		PRINT_ERR("Create ucom_tx_task error!\n");
1116 		return (ret);
1117 	}
1118 
1119 	(void)memset_s(&stappTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
1120 	stappTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ucom_rx_task;
1121 	stappTask.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
1122 	stappTask.pcName =		 "u3g_rx_Task";
1123 	stappTask.usTaskPrio =	 9;
1124 	stappTask.uwResved   =	 LOS_TASK_STATUS_DETACHED;
1125 	ret = LOS_TaskCreate(&g_u3g_rx_taskid, &stappTask);
1126 	if (ret != LOS_OK) {
1127 		PRINT_ERR("Create ucom_rx_task error!\n");
1128 		return (ret);
1129 	}
1130 
1131 	return (0);
1132 }
1133 
1134 static UINT32
u3g_tx_deinit(VOID)1135 u3g_tx_deinit(VOID)
1136 {
1137 	UINT32 ret;
1138 
1139 	ret = LOS_TaskDelete(g_u3g_tx_taskid);
1140 	if (ret != LOS_OK) {
1141 		return (ret);
1142 	}
1143 
1144 	ret = LOS_TaskDelete(g_u3g_rx_taskid);
1145 	if (ret != LOS_OK) {
1146 		return (ret);
1147 	}
1148 
1149 	ret = LOS_QueueDelete(m_uw_ucom_handler_queue);
1150 	if (ret != LOS_OK) {
1151 		return (ret);
1152 	}
1153 
1154 	return (LOS_OK);
1155 }
1156 
1157 static void
ucom_tx_task(void)1158 ucom_tx_task(void)
1159 {
1160 	ucom_handler_item_s *p_ucom_tx_handler;
1161 	UINT32 ret;
1162 	int err;
1163 
1164 	ret = LOS_MemboxInit(m_auc_ucom_handler_pool, sizeof(m_auc_ucom_handler_pool),
1165 						    sizeof(ucom_handler_item_s));
1166 	if (ret != LOS_OK) {
1167 		PRINTK("%s error!\n", __FUNCTION__);
1168 		return;
1169 	}
1170 
1171 	ret = LOS_QueueCreate(NULL, 8, &m_uw_ucom_handler_queue, 0, sizeof(ucom_handler_item_s));
1172 	if (ret != LOS_OK) {
1173 		PRINTK("%s error!\n", __FUNCTION__);
1174 		return;
1175 	}
1176 
1177 	tx_worked = 1;
1178 	for ( ; ; ) {
1179 		ret = LOS_QueueRead(m_uw_ucom_handler_queue, &p_ucom_tx_handler,
1180 							    sizeof(ucom_handler_item_s), LOS_WAIT_FOREVER);
1181 		if (ret == LOS_OK) {
1182 			if (p_ucom_tx_handler != NULL) {
1183 				if (tty_fd < 0) {
1184 					PRINTK("Please open ttyUBS0 first!\n");
1185 				} else {
1186 					err = write(tty_fd, p_ucom_tx_handler->p_ucom_tx_data,
1187 							    p_ucom_tx_handler->length);
1188 					if (err < 0) {
1189 					}
1190 				}
1191 				if (p_ucom_tx_handler->p_ucom_tx_data != NULL) {
1192 					free(p_ucom_tx_handler->p_ucom_tx_data);
1193 					p_ucom_tx_handler->p_ucom_tx_data = NULL;
1194 				}
1195 				if (p_ucom_tx_handler != NULL) {
1196 					(void)LOS_MemboxFree(m_auc_ucom_handler_pool,
1197 									    p_ucom_tx_handler);
1198 					p_ucom_tx_handler = NULL;
1199 				}
1200 			}
1201 		}
1202 	}
1203 }
1204 
1205 extern struct netif *pnetif_usb0;
1206 #ifdef LOSCFG_NET_LWIP_SACK
1207 uint32_t
u3g_write_from_shell(int argc,const char ** argv)1208 u3g_write_from_shell(int argc, const char **argv)
1209 {
1210 	ucom_handler_item_s *p_ucom_tx_handler;
1211 	char *buf;
1212 	int ret;
1213 	size_t len;
1214 
1215 	if (tx_worked == 0) {
1216 		PRINTK("u3g : no usb 3g/4g modem worked!\n");
1217 		return (LOS_NOK);
1218 	}
1219 
1220 	if (argv == NULL) {
1221 		PRINTK("u3g : please enter AT command!\n");
1222 		return (LOS_NOK);
1223 	}
1224 
1225 	if (argc > 1) {
1226 		PRINTK("u3g : only one argc supported!\n");
1227 		return (LOS_NOK);
1228 	}
1229 
1230 	if (((argv[0][0]=='A') && (argv[0][1]=='T')) || ((argv[0][0]=='a') && (argv[0][1]=='t'))) {
1231 		p_ucom_tx_handler = (ucom_handler_item_s *)LOS_MemboxAlloc(m_auc_ucom_handler_pool);
1232 		if (p_ucom_tx_handler != NULL) {
1233 			len = strlen(argv[0]);
1234 			if (len == 0) {
1235 				(void)LOS_MemboxFree(m_auc_ucom_handler_pool, p_ucom_tx_handler);
1236 				return (LOS_NOK);
1237 			}
1238 
1239 			buf = (char *)malloc(len + 2);
1240 			if (buf == NULL) {
1241 				(void)LOS_MemboxFree(m_auc_ucom_handler_pool, p_ucom_tx_handler);
1242 				return (LOS_NOK);
1243 			}
1244 
1245 			ret = memcpy_s(buf, (len + 2), argv[0], len);
1246 			if (ret != EOK) {
1247 				free(buf);
1248 				(void)LOS_MemboxFree(m_auc_ucom_handler_pool, p_ucom_tx_handler);
1249 				return (LOS_NOK);
1250 			}
1251 			buf[len] = 0xd;
1252 			buf[len+1] = 0xa;
1253 
1254 			p_ucom_tx_handler->length = len + 2;
1255 			p_ucom_tx_handler->p_ucom_tx_data = (void *)buf;
1256 			if (LOS_QueueWrite(m_uw_ucom_handler_queue, p_ucom_tx_handler,
1257 				    sizeof(UINT32), LOS_NO_WAIT)) {
1258 				(void)LOS_MemboxFree(m_auc_ucom_handler_pool, p_ucom_tx_handler);
1259 			}
1260 		}
1261 	} else if (strcmp("dhcp", argv[0]) == 0) {
1262 		(void)netifapi_dhcp_start(pnetif_usb0);
1263 		while (netifapi_dhcp_is_bound(pnetif_usb0) == 0) {
1264 			(void)sleep(1);
1265 		}
1266 		dprintf("\n----- DHCP success -----\n");
1267 	} else if (strcmp("open", argv[0]) == 0) {
1268 		tty_fd = open("/dev/ttyUSB0", O_RDWR);
1269 		if (tty_fd < 0) {
1270 			PRINTK("open /dev/ttyUSB0 error! errno %d\n", tty_fd);
1271 			return (LOS_NOK);
1272 		}
1273 	} else if (strcmp("close", argv[0]) == 0) {
1274 		if (tty_fd > 0) {
1275 			(void)close(tty_fd);
1276 			tty_fd = -1;
1277 		} else {
1278 			PRINTK("please first open /dev/ttyUSB0\n");
1279 			return (LOS_NOK);
1280 		}
1281 	} else {
1282 		PRINTK("u3g : please enter AT command!\n");
1283 		return (LOS_NOK);
1284 	}
1285 
1286 	return (LOS_OK);
1287 }
1288 #endif
1289 
1290 UINT8 m_auc_tty_usb_handler_pool[sizeof(OS_MEMBOX_S) +
1291 	    ((sizeof(ucom_handler_item_s) + 3) & (~3)) * 8];
1292 UINT32 m_uw_tty_usb_handler_queue;
1293 pthread_mutex_t tty_usb_mutex;
1294 
1295 static int
tty_usb_queue_init(void)1296 tty_usb_queue_init(void)
1297 {
1298 	UINT32 ret;
1299 
1300 	(void)pthread_mutex_init(&tty_usb_mutex, NULL);
1301 
1302 	ret = LOS_MemboxInit(m_auc_tty_usb_handler_pool,
1303 						    sizeof(m_auc_tty_usb_handler_pool), sizeof(ucom_handler_item_s));
1304 	if (ret != LOS_OK) {
1305 		dprintf("%s error!\n", __FUNCTION__);
1306 		return (EINVAL);
1307 	}
1308 
1309 	ret = LOS_QueueCreate(NULL, 8, &m_uw_tty_usb_handler_queue,
1310 			    0, sizeof(ucom_handler_item_s));
1311 	if (ret != LOS_OK) {
1312 		dprintf("%s error!\n", __FUNCTION__);
1313 		return (EINVAL);
1314 	}
1315 
1316 	return (ENOERR);
1317 }
1318 
1319 static void
tty_usb_queue_delete(void)1320 tty_usb_queue_delete(void)
1321 {
1322 	(void)LOS_QueueDelete(m_uw_tty_usb_handler_queue);
1323 }
1324 
1325 static int
tty_usb_write_wait(void)1326 tty_usb_write_wait(void)
1327 {
1328 	ucom_handler_item_s *ptty_usb_write_handler;
1329 	UINT32 ret;
1330 	unsigned int write_len = 0;
1331 
1332 	(void)pthread_mutex_lock(&tty_usb_mutex);
1333 
1334 	ret = LOS_QueueRead(m_uw_tty_usb_handler_queue, &ptty_usb_write_handler,
1335 						    sizeof(ucom_handler_item_s), LOS_WAIT_FOREVER);
1336 	if (ret == LOS_OK) {
1337 		if (ptty_usb_write_handler != NULL) {
1338 			write_len = ptty_usb_write_handler->length;
1339 			(VOID)LOS_MemboxFree(m_auc_tty_usb_handler_pool, ptty_usb_write_handler);
1340 		}
1341 	}
1342 	(void)pthread_mutex_unlock(&tty_usb_mutex);
1343 
1344 	return ((int)write_len);
1345 }
1346 
1347 static int
tty_usb_open(struct file * filep)1348 tty_usb_open(struct file *filep)
1349 {
1350 	struct drv_data *drvData = (struct drv_data *)filep->f_vnode->data;
1351 	struct ucom_softc *sc = (struct ucom_softc *)drvData->priv;
1352 	int ret;
1353 
1354 	UCOM_MTX_LOCK(sc);
1355 	if(tty_usb_queue_init() != ENOERR) {
1356 		UCOM_MTX_UNLOCK(sc);
1357 		return (-EINVAL);
1358 	}
1359 
1360 	ret = -ucom_open(sc);
1361 	UCOM_MTX_UNLOCK(sc);
1362 
1363 	return (ret);
1364 }
1365 
1366 static int
tty_usb_close(struct file * filep)1367 tty_usb_close(struct file *filep)
1368 {
1369 	struct drv_data *drvData = (struct drv_data *)filep->f_vnode->data;
1370 	struct ucom_softc *sc = (struct ucom_softc *)drvData->priv;
1371 
1372 	UCOM_MTX_LOCK(sc);
1373 	tty_usb_queue_delete();
1374 	ucom_close(sc);
1375 	UCOM_MTX_UNLOCK(sc);
1376 
1377 	return (0);
1378 }
1379 
1380 static ssize_t
tty_usb_read(struct file * filep,char * buffer,size_t buflen)1381 tty_usb_read(struct file *filep, char *buffer, size_t buflen)
1382 {
1383 	struct drv_data *drvData = (struct drv_data *)filep->f_vnode->data;
1384 	struct ucom_softc *sc = (struct ucom_softc *)drvData->priv;
1385 	int read_len = -1;
1386 	int ret;
1387 	UCOM_MTX_LOCK(sc);
1388 
1389 	if (ucom_cons_rx_low != ucom_cons_rx_high) {
1390 		unsigned int temp;
1391 
1392 		/* get total TX length */
1393 		temp = ucom_cons_rx_high - ucom_cons_rx_low;
1394 		temp %= UCOM_CONS_BUFSIZE;
1395 
1396 		if (temp > buflen)
1397 			temp = buflen;
1398 
1399 		/* copy in data */
1400 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_low)) {
1401 			unsigned int fisrt_len = (UCOM_CONS_BUFSIZE - ucom_cons_rx_low);
1402 			ret = usbd_copy_to_user(buffer, buflen, ucom_cons_rx_buf + ucom_cons_rx_low, fisrt_len);
1403 			if (ret != EOK) {
1404 				UCOM_MTX_UNLOCK(sc);
1405 				usb_err("memcpy_s failed!, ret:%d\n", ret);
1406 				return (0);
1407 			}
1408 			ret = usbd_copy_to_user(buffer + fisrt_len, (buflen - fisrt_len),
1409 									ucom_cons_rx_buf, temp - fisrt_len);
1410 			if (ret != EOK) {
1411 				UCOM_MTX_UNLOCK(sc);
1412 				usb_err("memcpy_s failed!, ret:%d\n", ret);
1413 				return (0);
1414 			}
1415 			PRINTK("len1 : %d ; len2 : %d \n", fisrt_len, temp);
1416 		}else {
1417 			ret = usbd_copy_to_user(buffer, buflen, ucom_cons_rx_buf + ucom_cons_rx_low, temp);
1418 			if (ret != EOK) {
1419 				UCOM_MTX_UNLOCK(sc);
1420 				usb_err("memcpy_s failed!, ret:%d\n", ret);
1421 				return (0);
1422 			}
1423 		}
1424 
1425 		/* update counters */
1426 		ucom_cons_rx_low += temp;
1427 		ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1428 
1429 		/* store actual length */
1430 		read_len = temp;
1431 	}
1432 	/* start USB transfers */
1433 	ucom_outwakeup(sc);
1434 
1435 	UCOM_MTX_UNLOCK(sc);
1436 	return (read_len);
1437 }
1438 
1439 static ssize_t
tty_usb_write(struct file * filep,const char * buffer,size_t buflen)1440 tty_usb_write(struct file *filep, const char *buffer, size_t buflen)
1441 {
1442 	struct drv_data *drvData = (struct drv_data *)filep->f_vnode->data;
1443 	struct ucom_softc *sc = (struct ucom_softc *)drvData->priv;
1444 
1445 	tx_data_copy_in(sc, (void *)buffer, buflen);
1446 	ucom_outwakeup(sc);
1447 
1448 	return (tty_usb_write_wait());
1449 }
1450 
1451 #undef USB_DEBUG_VAR
1452