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