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