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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1322 tty_usb_queue_delete(void) 1323 { 1324 (void)LOS_QueueDelete(m_uw_tty_usb_handler_queue); 1325 } 1326 1327 static int 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 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 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 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 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