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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1326 tty_usb_queue_delete(void) 1327 { 1328 (void)LOS_QueueDelete(m_uw_tty_usb_handler_queue); 1329 } 1330 1331 static int 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 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 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 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 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