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