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