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