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