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