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