1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 5f9f848faSopenharmony_ci * 6f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 7f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 8f9f848faSopenharmony_ci * are met: 9f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 10f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 11f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 12f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 13f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 14f9f848faSopenharmony_ci * 15f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25f9f848faSopenharmony_ci * SUCH DAMAGE. 26f9f848faSopenharmony_ci */ 27f9f848faSopenharmony_ci 28f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 29f9f848faSopenharmony_ci 30f9f848faSopenharmony_cistruct usb_process usb_process[USB_PROC_MAX]; 31f9f848faSopenharmony_cistruct mtx sched_lock; 32f9f848faSopenharmony_ci 33f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 34f9f848faSopenharmony_ci#define USB_DEBUG_VAR usb_proc_debug 35f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 36f9f848faSopenharmony_cistatic int usb_proc_debug; 37f9f848faSopenharmony_civoid 38f9f848faSopenharmony_ciusb_process_debug_func(int level) 39f9f848faSopenharmony_ci{ 40f9f848faSopenharmony_ci usb_proc_debug = level; 41f9f848faSopenharmony_ci PRINTK("The level of usb process debug is %d\n", level); 42f9f848faSopenharmony_ci} 43f9f848faSopenharmony_ciDEBUG_MODULE(process, usb_process_debug_func); 44f9f848faSopenharmony_ci#endif 45f9f848faSopenharmony_ci 46f9f848faSopenharmony_ciSPIN_LOCK_INIT(g_usb_process_queue_spinlock); 47f9f848faSopenharmony_ci 48f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 49f9f848faSopenharmony_ci * usb_process 50f9f848faSopenharmony_ci * 51f9f848faSopenharmony_ci * This function is the USB process dispatcher. 52f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 53f9f848faSopenharmony_cistatic void* 54f9f848faSopenharmony_ciusb_process_thread(UINTPTR para) 55f9f848faSopenharmony_ci{ 56f9f848faSopenharmony_ci struct usb_process *up = (struct usb_process*)para; 57f9f848faSopenharmony_ci struct usb_proc_msg *pm; 58f9f848faSopenharmony_ci struct thread *td; 59f9f848faSopenharmony_ci uint32_t int_save; 60f9f848faSopenharmony_ci 61f9f848faSopenharmony_ci /* in case of attach error, check for suspended */ 62f9f848faSopenharmony_ci USB_THREAD_SUSPEND_CHECK(); 63f9f848faSopenharmony_ci 64f9f848faSopenharmony_ci /* adjust priority */ 65f9f848faSopenharmony_ci td = (struct thread *)(UINTPTR)curthread; 66f9f848faSopenharmony_ci thread_lock(td); 67f9f848faSopenharmony_ci sched_prio(td, up->up_prio); 68f9f848faSopenharmony_ci thread_unlock(td); 69f9f848faSopenharmony_ci 70f9f848faSopenharmony_ci USB_MTX_LOCK(up->up_mtx); 71f9f848faSopenharmony_ci 72f9f848faSopenharmony_ci up->up_curtd = td; 73f9f848faSopenharmony_ci while (1) { 74f9f848faSopenharmony_ci if (up->up_gone) 75f9f848faSopenharmony_ci break; 76f9f848faSopenharmony_ci 77f9f848faSopenharmony_ci /* 78f9f848faSopenharmony_ci * NOTE to reimplementors: dequeueing a command from the 79f9f848faSopenharmony_ci * "used" queue and executing it must be atomic, with regard 80f9f848faSopenharmony_ci * to the "up_mtx" mutex. That means any attempt to queue a 81f9f848faSopenharmony_ci * command by another thread must be blocked until either: 82f9f848faSopenharmony_ci * 83f9f848faSopenharmony_ci * 1) the command sleeps 84f9f848faSopenharmony_ci * 85f9f848faSopenharmony_ci * 2) the command returns 86f9f848faSopenharmony_ci * 87f9f848faSopenharmony_ci * Here is a practical example that shows how this helps 88f9f848faSopenharmony_ci * solving a problem: 89f9f848faSopenharmony_ci * 90f9f848faSopenharmony_ci * Assume that you want to set the baud rate on a USB serial 91f9f848faSopenharmony_ci * device. During the programming of the device you don't 92f9f848faSopenharmony_ci * want to receive nor transmit any data, because it will be 93f9f848faSopenharmony_ci * garbage most likely anyway. The programming of our USB 94f9f848faSopenharmony_ci * device takes 20 milliseconds and it needs to call 95f9f848faSopenharmony_ci * functions that sleep. 96f9f848faSopenharmony_ci * 97f9f848faSopenharmony_ci * Non-working solution: Before we queue the programming 98f9f848faSopenharmony_ci * command, we stop transmission and reception of data. Then 99f9f848faSopenharmony_ci * we queue a programming command. At the end of the 100f9f848faSopenharmony_ci * programming command we enable transmission and reception 101f9f848faSopenharmony_ci * of data. 102f9f848faSopenharmony_ci * 103f9f848faSopenharmony_ci * Problem: If a second programming command is queued while the 104f9f848faSopenharmony_ci * first one is sleeping, we end up enabling transmission 105f9f848faSopenharmony_ci * and reception of data too early. 106f9f848faSopenharmony_ci * 107f9f848faSopenharmony_ci * Working solution: Before we queue the programming command, 108f9f848faSopenharmony_ci * we stop transmission and reception of data. Then we queue 109f9f848faSopenharmony_ci * a programming command. Then we queue a second command 110f9f848faSopenharmony_ci * that only enables transmission and reception of data. 111f9f848faSopenharmony_ci * 112f9f848faSopenharmony_ci * Why it works: If a second programming command is queued 113f9f848faSopenharmony_ci * while the first one is sleeping, then the queueing of a 114f9f848faSopenharmony_ci * second command to enable the data transfers, will cause 115f9f848faSopenharmony_ci * the previous one, which is still on the queue, to be 116f9f848faSopenharmony_ci * removed from the queue, and re-inserted after the last 117f9f848faSopenharmony_ci * baud rate programming command, which then gives the 118f9f848faSopenharmony_ci * desired result. 119f9f848faSopenharmony_ci */ 120f9f848faSopenharmony_ci 121f9f848faSopenharmony_ci LOS_SpinLockSave(&g_usb_process_queue_spinlock, &int_save); 122f9f848faSopenharmony_ci pm = TAILQ_FIRST(&up->up_qhead); 123f9f848faSopenharmony_ci LOS_SpinUnlockRestore(&g_usb_process_queue_spinlock, int_save); 124f9f848faSopenharmony_ci if (pm) { 125f9f848faSopenharmony_ci DPRINTF("Message pm=%p, cb=%p (enter)\n", 126f9f848faSopenharmony_ci pm, pm->pm_callback); 127f9f848faSopenharmony_ci 128f9f848faSopenharmony_ci if (pm->pm_callback) 129f9f848faSopenharmony_ci (pm->pm_callback) (pm); 130f9f848faSopenharmony_ci 131f9f848faSopenharmony_ci LOS_SpinLockSave(&g_usb_process_queue_spinlock, &int_save); 132f9f848faSopenharmony_ci if (pm == TAILQ_FIRST(&up->up_qhead)) { 133f9f848faSopenharmony_ci /* nothing changed */ 134f9f848faSopenharmony_ci TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 135f9f848faSopenharmony_ci pm->pm_qentry.tqe_prev = NULL; 136f9f848faSopenharmony_ci } 137f9f848faSopenharmony_ci LOS_SpinUnlockRestore(&g_usb_process_queue_spinlock, int_save); 138f9f848faSopenharmony_ci DPRINTF("Message pm=%p (leave)\n", pm); 139f9f848faSopenharmony_ci 140f9f848faSopenharmony_ci continue; 141f9f848faSopenharmony_ci } 142f9f848faSopenharmony_ci /* end if messages - check if anyone is waiting for sync */ 143f9f848faSopenharmony_ci if (up->up_dsleep) { 144f9f848faSopenharmony_ci up->up_dsleep = 0; 145f9f848faSopenharmony_ci (void)cv_broadcast(&up->up_drain); 146f9f848faSopenharmony_ci } 147f9f848faSopenharmony_ci up->up_msleep = 1; 148f9f848faSopenharmony_ci (void)cv_wait(&up->up_cv, up->up_mtx); 149f9f848faSopenharmony_ci } 150f9f848faSopenharmony_ci 151f9f848faSopenharmony_ci up->up_ptr = NULL; 152f9f848faSopenharmony_ci (void)cv_signal(&up->up_cv); 153f9f848faSopenharmony_ci USB_MTX_UNLOCK(up->up_mtx); 154f9f848faSopenharmony_ci USB_THREAD_EXIT(0); 155f9f848faSopenharmony_ci return NULL; 156f9f848faSopenharmony_ci} 157f9f848faSopenharmony_ci 158f9f848faSopenharmony_ciuint32_t 159f9f848faSopenharmony_ciusb_os_task_creat(pthread_t *taskid, TSK_ENTRY_FUNC func, uint32_t prio, const char *nm, UINTPTR para) 160f9f848faSopenharmony_ci{ 161f9f848faSopenharmony_ci uint32_t ret; 162f9f848faSopenharmony_ci TSK_INIT_PARAM_S attr; 163f9f848faSopenharmony_ci 164f9f848faSopenharmony_ci (void)memset_s(&attr, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 165f9f848faSopenharmony_ci 166f9f848faSopenharmony_ci attr.pfnTaskEntry = func; 167f9f848faSopenharmony_ci attr.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 168f9f848faSopenharmony_ci attr.auwArgs[0] = (UINTPTR)para; 169f9f848faSopenharmony_ci attr.usTaskPrio = prio; 170f9f848faSopenharmony_ci attr.pcName = (char *)nm; 171f9f848faSopenharmony_ci attr.uwResved = LOS_TASK_STATUS_DETACHED; 172f9f848faSopenharmony_ci 173f9f848faSopenharmony_ci ret = LOS_TaskCreate((uint32_t *)taskid, &attr); 174f9f848faSopenharmony_ci if (ret != LOS_OK) { 175f9f848faSopenharmony_ci PRINTK("create %s task error!\n",nm); 176f9f848faSopenharmony_ci } 177f9f848faSopenharmony_ci return (ret); 178f9f848faSopenharmony_ci} 179f9f848faSopenharmony_ci 180f9f848faSopenharmony_ciuint32_t 181f9f848faSopenharmony_ciusb_os_task_delete(pthread_t taskid) 182f9f848faSopenharmony_ci{ 183f9f848faSopenharmony_ci uint32_t ret; 184f9f848faSopenharmony_ci 185f9f848faSopenharmony_ci ret = LOS_TaskDelete(taskid); 186f9f848faSopenharmony_ci if (ret != LOS_OK) { 187f9f848faSopenharmony_ci PRINTK("delete task error!\n"); 188f9f848faSopenharmony_ci } 189f9f848faSopenharmony_ci return (ret); 190f9f848faSopenharmony_ci} 191f9f848faSopenharmony_ci 192f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 193f9f848faSopenharmony_ci * usb_proc_create 194f9f848faSopenharmony_ci * 195f9f848faSopenharmony_ci * This function will create a process using the given "prio" that can 196f9f848faSopenharmony_ci * execute callbacks. The mutex pointed to by "p_mtx" will be applied 197f9f848faSopenharmony_ci * before calling the callbacks and released after that the callback 198f9f848faSopenharmony_ci * has returned. The structure pointed to by "up" is assumed to be 199f9f848faSopenharmony_ci * zeroed before this function is called. 200f9f848faSopenharmony_ci * 201f9f848faSopenharmony_ci * Return values: 202f9f848faSopenharmony_ci * 0: success 203f9f848faSopenharmony_ci * Else: failure 204f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 205f9f848faSopenharmony_ciint 206f9f848faSopenharmony_ciusb_proc_create(struct usb_process *up, struct mtx *p_mtx, 207f9f848faSopenharmony_ci const char *pmesg, uint8_t prio) 208f9f848faSopenharmony_ci{ 209f9f848faSopenharmony_ci uint32_t ret; 210f9f848faSopenharmony_ci pthread_t td = 0; 211f9f848faSopenharmony_ci up->up_mtx = p_mtx; 212f9f848faSopenharmony_ci up->up_prio = prio; 213f9f848faSopenharmony_ci 214f9f848faSopenharmony_ci TAILQ_INIT(&up->up_qhead); 215f9f848faSopenharmony_ci 216f9f848faSopenharmony_ci cv_init(&up->up_cv, "-"); 217f9f848faSopenharmony_ci cv_init(&up->up_drain, "usbdrain"); 218f9f848faSopenharmony_ci 219f9f848faSopenharmony_ci ret = usb_os_task_creat(&td, (TSK_ENTRY_FUNC)usb_process_thread, prio, pmesg, (UINTPTR)up); 220f9f848faSopenharmony_ci if (ret != LOS_OK) { 221f9f848faSopenharmony_ci DPRINTFN(0, "Unable to create USB process."); 222f9f848faSopenharmony_ci up->up_ptr = NULL; 223f9f848faSopenharmony_ci goto error; 224f9f848faSopenharmony_ci } 225f9f848faSopenharmony_ci up->up_ptr = (struct thread *)(UINTPTR)td; 226f9f848faSopenharmony_ci return (0); 227f9f848faSopenharmony_ci 228f9f848faSopenharmony_cierror: 229f9f848faSopenharmony_ci usb_proc_free(up); 230f9f848faSopenharmony_ci return (ENOMEM); 231f9f848faSopenharmony_ci} 232f9f848faSopenharmony_ci 233f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 234f9f848faSopenharmony_ci * usb_proc_free 235f9f848faSopenharmony_ci * 236f9f848faSopenharmony_ci * NOTE: If the structure pointed to by "up" is all zero, this 237f9f848faSopenharmony_ci * function does nothing. 238f9f848faSopenharmony_ci * 239f9f848faSopenharmony_ci * NOTE: Messages that are pending on the process queue will not be 240f9f848faSopenharmony_ci * removed nor called. 241f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 242f9f848faSopenharmony_civoid 243f9f848faSopenharmony_ciusb_proc_free(struct usb_process *up) 244f9f848faSopenharmony_ci{ 245f9f848faSopenharmony_ci /* check if not initialised */ 246f9f848faSopenharmony_ci if (up->up_mtx == NULL) 247f9f848faSopenharmony_ci return; 248f9f848faSopenharmony_ci 249f9f848faSopenharmony_ci usb_proc_drain(up); 250f9f848faSopenharmony_ci 251f9f848faSopenharmony_ci cv_destroy(&up->up_cv); 252f9f848faSopenharmony_ci cv_destroy(&up->up_drain); 253f9f848faSopenharmony_ci 254f9f848faSopenharmony_ci /* make sure that we do not enter here again */ 255f9f848faSopenharmony_ci up->up_mtx = NULL; 256f9f848faSopenharmony_ci} 257f9f848faSopenharmony_ci 258f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 259f9f848faSopenharmony_ci * usb_proc_msignal 260f9f848faSopenharmony_ci * 261f9f848faSopenharmony_ci * This function will queue one of the passed USB process messages on 262f9f848faSopenharmony_ci * the USB process queue. The first message that is not already queued 263f9f848faSopenharmony_ci * will get queued. If both messages are already queued the one queued 264f9f848faSopenharmony_ci * last will be removed from the queue and queued in the end. The USB 265f9f848faSopenharmony_ci * process mutex must be locked when calling this function. This 266f9f848faSopenharmony_ci * function exploits the fact that a process can only do one callback 267f9f848faSopenharmony_ci * at a time. The message that was queued is returned. 268f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 269f9f848faSopenharmony_civoid * 270f9f848faSopenharmony_ciusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 271f9f848faSopenharmony_ci{ 272f9f848faSopenharmony_ci struct usb_proc_msg *pm0 = _pm0; 273f9f848faSopenharmony_ci struct usb_proc_msg *pm1 = _pm1; 274f9f848faSopenharmony_ci struct usb_proc_msg *pm2; 275f9f848faSopenharmony_ci usb_size_t d; 276f9f848faSopenharmony_ci uint8_t t; 277f9f848faSopenharmony_ci uint32_t int_save; 278f9f848faSopenharmony_ci 279f9f848faSopenharmony_ci /* check if gone, return dummy value */ 280f9f848faSopenharmony_ci if (up->up_gone) 281f9f848faSopenharmony_ci return (_pm0); 282f9f848faSopenharmony_ci 283f9f848faSopenharmony_ci t = 0; 284f9f848faSopenharmony_ci 285f9f848faSopenharmony_ci LOS_SpinLockSave(&g_usb_process_queue_spinlock, &int_save); 286f9f848faSopenharmony_ci if (pm0->pm_qentry.tqe_prev) { 287f9f848faSopenharmony_ci t |= 1; 288f9f848faSopenharmony_ci } 289f9f848faSopenharmony_ci if (pm1->pm_qentry.tqe_prev) { 290f9f848faSopenharmony_ci t |= 2; 291f9f848faSopenharmony_ci } 292f9f848faSopenharmony_ci if (t == 0) { 293f9f848faSopenharmony_ci /* 294f9f848faSopenharmony_ci * No entries are queued. Queue "pm0" and use the existing 295f9f848faSopenharmony_ci * message number. 296f9f848faSopenharmony_ci */ 297f9f848faSopenharmony_ci pm2 = pm0; 298f9f848faSopenharmony_ci } else if (t == 1) { 299f9f848faSopenharmony_ci /* Check if we need to increment the message number. */ 300f9f848faSopenharmony_ci if (pm0->pm_num == up->up_msg_num) { 301f9f848faSopenharmony_ci up->up_msg_num++; 302f9f848faSopenharmony_ci } 303f9f848faSopenharmony_ci pm2 = pm1; 304f9f848faSopenharmony_ci } else if (t == 2) { 305f9f848faSopenharmony_ci /* Check if we need to increment the message number. */ 306f9f848faSopenharmony_ci if (pm1->pm_num == up->up_msg_num) { 307f9f848faSopenharmony_ci up->up_msg_num++; 308f9f848faSopenharmony_ci } 309f9f848faSopenharmony_ci pm2 = pm0; 310f9f848faSopenharmony_ci } else if (t == 3) { 311f9f848faSopenharmony_ci /* 312f9f848faSopenharmony_ci * Both entries are queued. Re-queue the entry closest to 313f9f848faSopenharmony_ci * the end. 314f9f848faSopenharmony_ci */ 315f9f848faSopenharmony_ci d = (pm1->pm_num - pm0->pm_num); 316f9f848faSopenharmony_ci 317f9f848faSopenharmony_ci /* Check sign after subtraction */ 318f9f848faSopenharmony_ci if (d & 0x80000000) { 319f9f848faSopenharmony_ci pm2 = pm0; 320f9f848faSopenharmony_ci } else { 321f9f848faSopenharmony_ci pm2 = pm1; 322f9f848faSopenharmony_ci } 323f9f848faSopenharmony_ci 324f9f848faSopenharmony_ci TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 325f9f848faSopenharmony_ci pm2->pm_qentry.tqe_prev = NULL; 326f9f848faSopenharmony_ci } else { 327f9f848faSopenharmony_ci pm2 = NULL; /* panic - should not happen */ 328f9f848faSopenharmony_ci } 329f9f848faSopenharmony_ci 330f9f848faSopenharmony_ci DPRINTF(" t=%u, num=%u\n", t, up->up_msg_num); 331f9f848faSopenharmony_ci 332f9f848faSopenharmony_ci /* Put message last on queue */ 333f9f848faSopenharmony_ci 334f9f848faSopenharmony_ci pm2->pm_num = up->up_msg_num; 335f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 336f9f848faSopenharmony_ci LOS_SpinUnlockRestore(&g_usb_process_queue_spinlock, int_save); 337f9f848faSopenharmony_ci 338f9f848faSopenharmony_ci /* Check if we need to wakeup the USB process. */ 339f9f848faSopenharmony_ci 340f9f848faSopenharmony_ci up->up_msleep = 0; /* save "cv_signal()" calls */ 341f9f848faSopenharmony_ci (void)cv_signal(&up->up_cv); 342f9f848faSopenharmony_ci 343f9f848faSopenharmony_ci return (pm2); 344f9f848faSopenharmony_ci} 345f9f848faSopenharmony_ci 346f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 347f9f848faSopenharmony_ci * usb_proc_is_gone 348f9f848faSopenharmony_ci * 349f9f848faSopenharmony_ci * Return values: 350f9f848faSopenharmony_ci * 0: USB process is running 351f9f848faSopenharmony_ci * Else: USB process is tearing down 352f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 353f9f848faSopenharmony_ciuint8_t 354f9f848faSopenharmony_ciusb_proc_is_gone(struct usb_process *up) 355f9f848faSopenharmony_ci{ 356f9f848faSopenharmony_ci if (up->up_gone) { 357f9f848faSopenharmony_ci return (1); 358f9f848faSopenharmony_ci } 359f9f848faSopenharmony_ci 360f9f848faSopenharmony_ci /* 361f9f848faSopenharmony_ci * Allow calls when up_mtx is NULL, before the USB process 362f9f848faSopenharmony_ci * structure is initialised. 363f9f848faSopenharmony_ci */ 364f9f848faSopenharmony_ci if (up->up_mtx != NULL) { 365f9f848faSopenharmony_ci mtx_assert(up->up_mtx, MA_OWNED); 366f9f848faSopenharmony_ci } 367f9f848faSopenharmony_ci return (0); 368f9f848faSopenharmony_ci} 369f9f848faSopenharmony_ci 370f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 371f9f848faSopenharmony_ci * usb_proc_mwait 372f9f848faSopenharmony_ci * 373f9f848faSopenharmony_ci * This function will return when the USB process message pointed to 374f9f848faSopenharmony_ci * by "pm" is no longer on a queue. This function must be called 375f9f848faSopenharmony_ci * having "up->up_mtx" locked. 376f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 377f9f848faSopenharmony_civoid 378f9f848faSopenharmony_ciusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 379f9f848faSopenharmony_ci{ 380f9f848faSopenharmony_ci struct usb_proc_msg *pm0 = _pm0; 381f9f848faSopenharmony_ci struct usb_proc_msg *pm1 = _pm1; 382f9f848faSopenharmony_ci uint32_t int_save; 383f9f848faSopenharmony_ci 384f9f848faSopenharmony_ci /* check if gone */ 385f9f848faSopenharmony_ci if (up->up_gone) 386f9f848faSopenharmony_ci return; 387f9f848faSopenharmony_ci 388f9f848faSopenharmony_ci mtx_assert(up->up_mtx, MA_OWNED); 389f9f848faSopenharmony_ci 390f9f848faSopenharmony_ci if (up->up_curtd == (struct thread *)(UINTPTR)curthread) { 391f9f848faSopenharmony_ci LOS_SpinLockSave(&g_usb_process_queue_spinlock, &int_save); 392f9f848faSopenharmony_ci /* Just remove the messages from the queue. */ 393f9f848faSopenharmony_ci if (pm0->pm_qentry.tqe_prev) { 394f9f848faSopenharmony_ci TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 395f9f848faSopenharmony_ci pm0->pm_qentry.tqe_prev = NULL; 396f9f848faSopenharmony_ci } 397f9f848faSopenharmony_ci if (pm1->pm_qentry.tqe_prev) { 398f9f848faSopenharmony_ci TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 399f9f848faSopenharmony_ci pm1->pm_qentry.tqe_prev = NULL; 400f9f848faSopenharmony_ci } 401f9f848faSopenharmony_ci LOS_SpinUnlockRestore(&g_usb_process_queue_spinlock, int_save); 402f9f848faSopenharmony_ci } else 403f9f848faSopenharmony_ci while (pm0->pm_qentry.tqe_prev || 404f9f848faSopenharmony_ci pm1->pm_qentry.tqe_prev) { 405f9f848faSopenharmony_ci /* check if config thread is gone */ 406f9f848faSopenharmony_ci if (up->up_gone) 407f9f848faSopenharmony_ci break; 408f9f848faSopenharmony_ci up->up_dsleep = 1; 409f9f848faSopenharmony_ci (void)cv_wait(&up->up_drain, up->up_mtx); 410f9f848faSopenharmony_ci } 411f9f848faSopenharmony_ci} 412f9f848faSopenharmony_ci 413f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 414f9f848faSopenharmony_ci * usb_proc_drain 415f9f848faSopenharmony_ci * 416f9f848faSopenharmony_ci * This function will tear down an USB process, waiting for the 417f9f848faSopenharmony_ci * currently executing command to return. 418f9f848faSopenharmony_ci * 419f9f848faSopenharmony_ci * NOTE: If the structure pointed to by "up" is all zero, 420f9f848faSopenharmony_ci * this function does nothing. 421f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 422f9f848faSopenharmony_civoid 423f9f848faSopenharmony_ciusb_proc_drain(struct usb_process *up) 424f9f848faSopenharmony_ci{ 425f9f848faSopenharmony_ci /* check if not initialised */ 426f9f848faSopenharmony_ci if (up->up_mtx == NULL) { 427f9f848faSopenharmony_ci return; 428f9f848faSopenharmony_ci } 429f9f848faSopenharmony_ci 430f9f848faSopenharmony_ci /* handle special case with Giant */ 431f9f848faSopenharmony_ci if (up->up_mtx != &Giant) { 432f9f848faSopenharmony_ci mtx_assert(up->up_mtx, MA_NOTOWNED); 433f9f848faSopenharmony_ci } 434f9f848faSopenharmony_ci 435f9f848faSopenharmony_ci USB_MTX_LOCK(up->up_mtx); 436f9f848faSopenharmony_ci 437f9f848faSopenharmony_ci /* Set the gone flag */ 438f9f848faSopenharmony_ci 439f9f848faSopenharmony_ci up->up_gone = 1; 440f9f848faSopenharmony_ci 441f9f848faSopenharmony_ci while (up->up_ptr) { 442f9f848faSopenharmony_ci 443f9f848faSopenharmony_ci /* Check if we need to wakeup the USB process */ 444f9f848faSopenharmony_ci 445f9f848faSopenharmony_ci if (up->up_msleep || up->up_csleep) { 446f9f848faSopenharmony_ci up->up_msleep = 0; 447f9f848faSopenharmony_ci up->up_csleep = 0; 448f9f848faSopenharmony_ci (void)cv_signal(&up->up_cv); 449f9f848faSopenharmony_ci } 450f9f848faSopenharmony_ci (void)cv_wait(&up->up_cv, up->up_mtx); 451f9f848faSopenharmony_ci } 452f9f848faSopenharmony_ci /* Check if someone is waiting - should not happen */ 453f9f848faSopenharmony_ci 454f9f848faSopenharmony_ci if (up->up_dsleep) { 455f9f848faSopenharmony_ci up->up_dsleep = 0; 456f9f848faSopenharmony_ci (void)cv_broadcast(&up->up_drain); 457f9f848faSopenharmony_ci DPRINTF("WARNING: Someone is waiting " 458f9f848faSopenharmony_ci "for USB process drain!\n"); 459f9f848faSopenharmony_ci } 460f9f848faSopenharmony_ci USB_MTX_UNLOCK(up->up_mtx); 461f9f848faSopenharmony_ci} 462f9f848faSopenharmony_ci 463f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 464f9f848faSopenharmony_ci * usb_proc_rewakeup 465f9f848faSopenharmony_ci * 466f9f848faSopenharmony_ci * This function is called to re-wakeup the given USB 467f9f848faSopenharmony_ci * process. This usually happens after that the USB system has been in 468f9f848faSopenharmony_ci * polling mode, like during a panic. This function must be called 469f9f848faSopenharmony_ci * having "up->up_mtx" locked. 470f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 471f9f848faSopenharmony_civoid 472f9f848faSopenharmony_ciusb_proc_rewakeup(struct usb_process *up) 473f9f848faSopenharmony_ci{ 474f9f848faSopenharmony_ci /* check if not initialised */ 475f9f848faSopenharmony_ci if (up->up_mtx == NULL) 476f9f848faSopenharmony_ci return; 477f9f848faSopenharmony_ci /* check if gone */ 478f9f848faSopenharmony_ci if (up->up_gone) 479f9f848faSopenharmony_ci return; 480f9f848faSopenharmony_ci 481f9f848faSopenharmony_ci mtx_assert(up->up_mtx, MA_OWNED); 482f9f848faSopenharmony_ci 483f9f848faSopenharmony_ci if (up->up_msleep == 0) { 484f9f848faSopenharmony_ci /* re-wakeup */ 485f9f848faSopenharmony_ci (void)cv_signal(&up->up_cv); 486f9f848faSopenharmony_ci } 487f9f848faSopenharmony_ci} 488f9f848faSopenharmony_ci 489f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 490f9f848faSopenharmony_ci * usb_proc_is_called_from 491f9f848faSopenharmony_ci * 492f9f848faSopenharmony_ci * This function will return non-zero if called from inside the USB 493f9f848faSopenharmony_ci * process passed as first argument. Else this function returns zero. 494f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 495f9f848faSopenharmony_ciint 496f9f848faSopenharmony_ciusb_proc_is_called_from(struct usb_process *up) 497f9f848faSopenharmony_ci{ 498f9f848faSopenharmony_ci return (up->up_curtd == (struct thread *)(UINTPTR)curthread); 499f9f848faSopenharmony_ci} 500f9f848faSopenharmony_ci 501f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 502