1141a761fSMarkus Pfeiffer /* $FreeBSD: head/sys/dev/usb/usb_process.c 267992 2014-06-28 03:56:17Z hselasky $ */
212bd3c8bSSascha Wildner /*-
312bd3c8bSSascha Wildner * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
412bd3c8bSSascha Wildner *
512bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without
612bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions
712bd3c8bSSascha Wildner * are met:
812bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright
912bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer.
1012bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the
1212bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution.
1312bd3c8bSSascha Wildner *
1412bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1512bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1612bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1712bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1812bd3c8bSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1912bd3c8bSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2012bd3c8bSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2112bd3c8bSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2212bd3c8bSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2312bd3c8bSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2412bd3c8bSSascha Wildner * SUCH DAMAGE.
2512bd3c8bSSascha Wildner */
2612bd3c8bSSascha Wildner
2712bd3c8bSSascha Wildner #define USB_DEBUG_VAR usb_proc_debug
2812bd3c8bSSascha Wildner
2912bd3c8bSSascha Wildner #include <sys/stdint.h>
3012bd3c8bSSascha Wildner #include <sys/param.h>
3112bd3c8bSSascha Wildner #include <sys/queue.h>
3212bd3c8bSSascha Wildner #include <sys/types.h>
3312bd3c8bSSascha Wildner #include <sys/systm.h>
3412bd3c8bSSascha Wildner #include <sys/kernel.h>
3512bd3c8bSSascha Wildner #include <sys/bus.h>
3612bd3c8bSSascha Wildner #include <sys/module.h>
3712bd3c8bSSascha Wildner #include <sys/lock.h>
3812bd3c8bSSascha Wildner #include <sys/condvar.h>
3912bd3c8bSSascha Wildner #include <sys/sysctl.h>
4012bd3c8bSSascha Wildner #include <sys/unistd.h>
4112bd3c8bSSascha Wildner #include <sys/callout.h>
4212bd3c8bSSascha Wildner #include <sys/malloc.h>
43*2b3f93eaSMatthew Dillon #include <sys/caps.h>
4412bd3c8bSSascha Wildner
45722d05c3SSascha Wildner #include <bus/u4b/usb.h>
46722d05c3SSascha Wildner #include <bus/u4b/usbdi.h>
47722d05c3SSascha Wildner #include <bus/u4b/usbdi_util.h>
48722d05c3SSascha Wildner #include <bus/u4b/usb_process.h>
49722d05c3SSascha Wildner #include <bus/u4b/usb_debug.h>
50722d05c3SSascha Wildner #include <bus/u4b/usb_util.h>
5112bd3c8bSSascha Wildner
5212bd3c8bSSascha Wildner #include <sys/proc.h>
5312bd3c8bSSascha Wildner #include <sys/kthread.h>
5412bd3c8bSSascha Wildner #include <sys/sched.h>
5512bd3c8bSSascha Wildner
5657bed822SMarkus Pfeiffer static struct proc *usbproc;
5712bd3c8bSSascha Wildner static int usb_pcount;
5812bd3c8bSSascha Wildner #define USB_THREAD_CREATE(f, s, p, ...) \
59722d05c3SSascha Wildner kthread_create((f), (s), (p), __VA_ARGS__)
6012bd3c8bSSascha Wildner #define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curproc)
61722d05c3SSascha Wildner #define USB_THREAD_SUSPEND(p) suspend_kproc(p,0)
62722d05c3SSascha Wildner #define USB_THREAD_EXIT(err) kthread_exit()
6312bd3c8bSSascha Wildner
6412bd3c8bSSascha Wildner #ifdef USB_DEBUG
6512bd3c8bSSascha Wildner static int usb_proc_debug;
6612bd3c8bSSascha Wildner
6712bd3c8bSSascha Wildner static SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process");
6812bd3c8bSSascha Wildner SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW, &usb_proc_debug, 0,
6912bd3c8bSSascha Wildner "Debug level");
7012bd3c8bSSascha Wildner
7112bd3c8bSSascha Wildner TUNABLE_INT("hw.usb.proc.debug", &usb_proc_debug);
7212bd3c8bSSascha Wildner #endif
7312bd3c8bSSascha Wildner
7412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
7512bd3c8bSSascha Wildner * usb_process
7612bd3c8bSSascha Wildner *
7712bd3c8bSSascha Wildner * This function is the USB process dispatcher.
7812bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
7912bd3c8bSSascha Wildner static void
usb_process(void * arg)8012bd3c8bSSascha Wildner usb_process(void *arg)
8112bd3c8bSSascha Wildner {
8212bd3c8bSSascha Wildner struct usb_process *up = arg;
8312bd3c8bSSascha Wildner struct usb_proc_msg *pm;
8412bd3c8bSSascha Wildner struct thread *td;
8512bd3c8bSSascha Wildner
8663da4a34SSascha Wildner #if 0 /* XXX Suspend here? */
8712bd3c8bSSascha Wildner /* in case of attach error, check for suspended */
8863da4a34SSascha Wildner USB_THREAD_SUSPEND_CHECK();
8963da4a34SSascha Wildner #endif
9012bd3c8bSSascha Wildner
9112bd3c8bSSascha Wildner /* adjust priority */
9212bd3c8bSSascha Wildner td = curthread;
93722d05c3SSascha Wildner lwkt_setpri(td, up->up_prio);
94722d05c3SSascha Wildner lockmgr(up->up_lock, LK_EXCLUSIVE);
9512bd3c8bSSascha Wildner
9612bd3c8bSSascha Wildner up->up_curtd = td;
9712bd3c8bSSascha Wildner
9812bd3c8bSSascha Wildner while (1) {
9912bd3c8bSSascha Wildner
10012bd3c8bSSascha Wildner if (up->up_gone)
10112bd3c8bSSascha Wildner break;
10212bd3c8bSSascha Wildner
10312bd3c8bSSascha Wildner /*
10412bd3c8bSSascha Wildner * NOTE to reimplementors: dequeueing a command from the
10512bd3c8bSSascha Wildner * "used" queue and executing it must be atomic, with regard
10612bd3c8bSSascha Wildner * to the "up_mtx" mutex. That means any attempt to queue a
10712bd3c8bSSascha Wildner * command by another thread must be blocked until either:
10812bd3c8bSSascha Wildner *
10912bd3c8bSSascha Wildner * 1) the command sleeps
11012bd3c8bSSascha Wildner *
11112bd3c8bSSascha Wildner * 2) the command returns
11212bd3c8bSSascha Wildner *
11312bd3c8bSSascha Wildner * Here is a practical example that shows how this helps
11412bd3c8bSSascha Wildner * solving a problem:
11512bd3c8bSSascha Wildner *
11612bd3c8bSSascha Wildner * Assume that you want to set the baud rate on a USB serial
11712bd3c8bSSascha Wildner * device. During the programming of the device you don't
11812bd3c8bSSascha Wildner * want to receive nor transmit any data, because it will be
11912bd3c8bSSascha Wildner * garbage most likely anyway. The programming of our USB
12012bd3c8bSSascha Wildner * device takes 20 milliseconds and it needs to call
12112bd3c8bSSascha Wildner * functions that sleep.
12212bd3c8bSSascha Wildner *
12312bd3c8bSSascha Wildner * Non-working solution: Before we queue the programming
12412bd3c8bSSascha Wildner * command, we stop transmission and reception of data. Then
12512bd3c8bSSascha Wildner * we queue a programming command. At the end of the
12612bd3c8bSSascha Wildner * programming command we enable transmission and reception
12712bd3c8bSSascha Wildner * of data.
12812bd3c8bSSascha Wildner *
12912bd3c8bSSascha Wildner * Problem: If a second programming command is queued while the
13012bd3c8bSSascha Wildner * first one is sleeping, we end up enabling transmission
13112bd3c8bSSascha Wildner * and reception of data too early.
13212bd3c8bSSascha Wildner *
13312bd3c8bSSascha Wildner * Working solution: Before we queue the programming command,
13412bd3c8bSSascha Wildner * we stop transmission and reception of data. Then we queue
13512bd3c8bSSascha Wildner * a programming command. Then we queue a second command
13612bd3c8bSSascha Wildner * that only enables transmission and reception of data.
13712bd3c8bSSascha Wildner *
13812bd3c8bSSascha Wildner * Why it works: If a second programming command is queued
13912bd3c8bSSascha Wildner * while the first one is sleeping, then the queueing of a
14012bd3c8bSSascha Wildner * second command to enable the data transfers, will cause
14112bd3c8bSSascha Wildner * the previous one, which is still on the queue, to be
14212bd3c8bSSascha Wildner * removed from the queue, and re-inserted after the last
14312bd3c8bSSascha Wildner * baud rate programming command, which then gives the
14412bd3c8bSSascha Wildner * desired result.
14512bd3c8bSSascha Wildner */
14612bd3c8bSSascha Wildner pm = TAILQ_FIRST(&up->up_qhead);
14712bd3c8bSSascha Wildner
14812bd3c8bSSascha Wildner if (pm) {
14912bd3c8bSSascha Wildner DPRINTF("Message pm=%p, cb=%p (enter)\n",
15012bd3c8bSSascha Wildner pm, pm->pm_callback);
15112bd3c8bSSascha Wildner
15212bd3c8bSSascha Wildner (pm->pm_callback) (pm);
15312bd3c8bSSascha Wildner
15412bd3c8bSSascha Wildner if (pm == TAILQ_FIRST(&up->up_qhead)) {
15512bd3c8bSSascha Wildner /* nothing changed */
15612bd3c8bSSascha Wildner TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
15712bd3c8bSSascha Wildner pm->pm_qentry.tqe_prev = NULL;
15812bd3c8bSSascha Wildner }
15912bd3c8bSSascha Wildner DPRINTF("Message pm=%p (leave)\n", pm);
16012bd3c8bSSascha Wildner
16112bd3c8bSSascha Wildner continue;
16212bd3c8bSSascha Wildner }
16312bd3c8bSSascha Wildner /* end if messages - check if anyone is waiting for sync */
16412bd3c8bSSascha Wildner if (up->up_dsleep) {
16512bd3c8bSSascha Wildner up->up_dsleep = 0;
16612bd3c8bSSascha Wildner cv_broadcast(&up->up_drain);
16712bd3c8bSSascha Wildner }
16812bd3c8bSSascha Wildner up->up_msleep = 1;
169722d05c3SSascha Wildner cv_wait(&up->up_cv, up->up_lock);
17012bd3c8bSSascha Wildner }
17112bd3c8bSSascha Wildner
17212bd3c8bSSascha Wildner up->up_ptr = NULL;
17312bd3c8bSSascha Wildner cv_signal(&up->up_cv);
174722d05c3SSascha Wildner lockmgr(up->up_lock, LK_RELEASE);
17557bed822SMarkus Pfeiffer
17612bd3c8bSSascha Wildner /* Clear the proc pointer if this is the last thread. */
17712bd3c8bSSascha Wildner if (--usb_pcount == 0)
17812bd3c8bSSascha Wildner usbproc = NULL;
17963da4a34SSascha Wildner
18012bd3c8bSSascha Wildner USB_THREAD_EXIT(0);
18112bd3c8bSSascha Wildner }
18212bd3c8bSSascha Wildner
18312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
18412bd3c8bSSascha Wildner * usb_proc_create
18512bd3c8bSSascha Wildner *
18612bd3c8bSSascha Wildner * This function will create a process using the given "prio" that can
18712bd3c8bSSascha Wildner * execute callbacks. The mutex pointed to by "p_mtx" will be applied
18812bd3c8bSSascha Wildner * before calling the callbacks and released after that the callback
18912bd3c8bSSascha Wildner * has returned. The structure pointed to by "up" is assumed to be
19012bd3c8bSSascha Wildner * zeroed before this function is called.
19112bd3c8bSSascha Wildner *
19212bd3c8bSSascha Wildner * Return values:
19312bd3c8bSSascha Wildner * 0: success
19412bd3c8bSSascha Wildner * Else: failure
19512bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
19612bd3c8bSSascha Wildner int
usb_proc_create(struct usb_process * up,struct lock * p_lock,const char * pmesg,uint8_t prio)197722d05c3SSascha Wildner usb_proc_create(struct usb_process *up, struct lock *p_lock,
19812bd3c8bSSascha Wildner const char *pmesg, uint8_t prio)
19912bd3c8bSSascha Wildner {
200722d05c3SSascha Wildner up->up_lock = p_lock;
20112bd3c8bSSascha Wildner up->up_prio = prio;
20212bd3c8bSSascha Wildner
20312bd3c8bSSascha Wildner TAILQ_INIT(&up->up_qhead);
20412bd3c8bSSascha Wildner
20512bd3c8bSSascha Wildner cv_init(&up->up_cv, "-");
20612bd3c8bSSascha Wildner cv_init(&up->up_drain, "usbdrain");
20712bd3c8bSSascha Wildner
20812bd3c8bSSascha Wildner if (USB_THREAD_CREATE(&usb_process, up,
20912bd3c8bSSascha Wildner &up->up_ptr, "%s", pmesg)) {
21012bd3c8bSSascha Wildner DPRINTFN(0, "Unable to create USB process.");
21112bd3c8bSSascha Wildner up->up_ptr = NULL;
21212bd3c8bSSascha Wildner goto error;
21312bd3c8bSSascha Wildner }
21412bd3c8bSSascha Wildner usb_pcount++;
21512bd3c8bSSascha Wildner return (0);
21612bd3c8bSSascha Wildner
21712bd3c8bSSascha Wildner error:
21812bd3c8bSSascha Wildner usb_proc_free(up);
21912bd3c8bSSascha Wildner return (ENOMEM);
22012bd3c8bSSascha Wildner }
22112bd3c8bSSascha Wildner
22212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
22312bd3c8bSSascha Wildner * usb_proc_free
22412bd3c8bSSascha Wildner *
22512bd3c8bSSascha Wildner * NOTE: If the structure pointed to by "up" is all zero, this
22612bd3c8bSSascha Wildner * function does nothing.
22712bd3c8bSSascha Wildner *
22812bd3c8bSSascha Wildner * NOTE: Messages that are pending on the process queue will not be
22912bd3c8bSSascha Wildner * removed nor called.
23012bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
23112bd3c8bSSascha Wildner void
usb_proc_free(struct usb_process * up)23212bd3c8bSSascha Wildner usb_proc_free(struct usb_process *up)
23312bd3c8bSSascha Wildner {
23412bd3c8bSSascha Wildner /* check if not initialised */
235722d05c3SSascha Wildner if (up->up_lock == NULL)
23612bd3c8bSSascha Wildner return;
23712bd3c8bSSascha Wildner
23812bd3c8bSSascha Wildner usb_proc_drain(up);
23912bd3c8bSSascha Wildner
24012bd3c8bSSascha Wildner cv_destroy(&up->up_cv);
24112bd3c8bSSascha Wildner cv_destroy(&up->up_drain);
24212bd3c8bSSascha Wildner
24312bd3c8bSSascha Wildner /* make sure that we do not enter here again */
244722d05c3SSascha Wildner up->up_lock = NULL;
24512bd3c8bSSascha Wildner }
24612bd3c8bSSascha Wildner
24712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
24812bd3c8bSSascha Wildner * usb_proc_msignal
24912bd3c8bSSascha Wildner *
25012bd3c8bSSascha Wildner * This function will queue one of the passed USB process messages on
25112bd3c8bSSascha Wildner * the USB process queue. The first message that is not already queued
25212bd3c8bSSascha Wildner * will get queued. If both messages are already queued the one queued
25312bd3c8bSSascha Wildner * last will be removed from the queue and queued in the end. The USB
25412bd3c8bSSascha Wildner * process mutex must be locked when calling this function. This
25512bd3c8bSSascha Wildner * function exploits the fact that a process can only do one callback
25612bd3c8bSSascha Wildner * at a time. The message that was queued is returned.
25712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
25812bd3c8bSSascha Wildner void *
usb_proc_msignal(struct usb_process * up,void * _pm0,void * _pm1)25912bd3c8bSSascha Wildner usb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
26012bd3c8bSSascha Wildner {
26112bd3c8bSSascha Wildner struct usb_proc_msg *pm0 = _pm0;
26212bd3c8bSSascha Wildner struct usb_proc_msg *pm1 = _pm1;
26312bd3c8bSSascha Wildner struct usb_proc_msg *pm2;
26412bd3c8bSSascha Wildner usb_size_t d;
26512bd3c8bSSascha Wildner uint8_t t;
26612bd3c8bSSascha Wildner
26712bd3c8bSSascha Wildner /* check if gone, return dummy value */
26812bd3c8bSSascha Wildner if (up->up_gone)
26912bd3c8bSSascha Wildner return (_pm0);
27012bd3c8bSSascha Wildner
2713a76bbe8SSascha Wildner KKASSERT(lockowned(up->up_lock));
27212bd3c8bSSascha Wildner
27312bd3c8bSSascha Wildner t = 0;
27412bd3c8bSSascha Wildner
27512bd3c8bSSascha Wildner if (pm0->pm_qentry.tqe_prev) {
27612bd3c8bSSascha Wildner t |= 1;
27712bd3c8bSSascha Wildner }
27812bd3c8bSSascha Wildner if (pm1->pm_qentry.tqe_prev) {
27912bd3c8bSSascha Wildner t |= 2;
28012bd3c8bSSascha Wildner }
28112bd3c8bSSascha Wildner if (t == 0) {
28212bd3c8bSSascha Wildner /*
28312bd3c8bSSascha Wildner * No entries are queued. Queue "pm0" and use the existing
28412bd3c8bSSascha Wildner * message number.
28512bd3c8bSSascha Wildner */
28612bd3c8bSSascha Wildner pm2 = pm0;
28712bd3c8bSSascha Wildner } else if (t == 1) {
28812bd3c8bSSascha Wildner /* Check if we need to increment the message number. */
28912bd3c8bSSascha Wildner if (pm0->pm_num == up->up_msg_num) {
29012bd3c8bSSascha Wildner up->up_msg_num++;
29112bd3c8bSSascha Wildner }
29212bd3c8bSSascha Wildner pm2 = pm1;
29312bd3c8bSSascha Wildner } else if (t == 2) {
29412bd3c8bSSascha Wildner /* Check if we need to increment the message number. */
29512bd3c8bSSascha Wildner if (pm1->pm_num == up->up_msg_num) {
29612bd3c8bSSascha Wildner up->up_msg_num++;
29712bd3c8bSSascha Wildner }
29812bd3c8bSSascha Wildner pm2 = pm0;
29912bd3c8bSSascha Wildner } else if (t == 3) {
30012bd3c8bSSascha Wildner /*
30112bd3c8bSSascha Wildner * Both entries are queued. Re-queue the entry closest to
30212bd3c8bSSascha Wildner * the end.
30312bd3c8bSSascha Wildner */
30412bd3c8bSSascha Wildner d = (pm1->pm_num - pm0->pm_num);
30512bd3c8bSSascha Wildner
30612bd3c8bSSascha Wildner /* Check sign after subtraction */
30712bd3c8bSSascha Wildner if (d & 0x80000000) {
30812bd3c8bSSascha Wildner pm2 = pm0;
30912bd3c8bSSascha Wildner } else {
31012bd3c8bSSascha Wildner pm2 = pm1;
31112bd3c8bSSascha Wildner }
31212bd3c8bSSascha Wildner
31312bd3c8bSSascha Wildner TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
31412bd3c8bSSascha Wildner } else {
31512bd3c8bSSascha Wildner pm2 = NULL; /* panic - should not happen */
31612bd3c8bSSascha Wildner }
31712bd3c8bSSascha Wildner
31812bd3c8bSSascha Wildner DPRINTF(" t=%u, num=%u\n", t, up->up_msg_num);
31912bd3c8bSSascha Wildner
32012bd3c8bSSascha Wildner /* Put message last on queue */
32112bd3c8bSSascha Wildner
32212bd3c8bSSascha Wildner pm2->pm_num = up->up_msg_num;
32312bd3c8bSSascha Wildner TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
32412bd3c8bSSascha Wildner
32512bd3c8bSSascha Wildner /* Check if we need to wakeup the USB process. */
32612bd3c8bSSascha Wildner
32712bd3c8bSSascha Wildner if (up->up_msleep) {
32812bd3c8bSSascha Wildner up->up_msleep = 0; /* save "cv_signal()" calls */
32912bd3c8bSSascha Wildner cv_signal(&up->up_cv);
33012bd3c8bSSascha Wildner }
33112bd3c8bSSascha Wildner return (pm2);
33212bd3c8bSSascha Wildner }
33312bd3c8bSSascha Wildner
33412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
33512bd3c8bSSascha Wildner * usb_proc_is_gone
33612bd3c8bSSascha Wildner *
33712bd3c8bSSascha Wildner * Return values:
33812bd3c8bSSascha Wildner * 0: USB process is running
33912bd3c8bSSascha Wildner * Else: USB process is tearing down
34012bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
34112bd3c8bSSascha Wildner uint8_t
usb_proc_is_gone(struct usb_process * up)34212bd3c8bSSascha Wildner usb_proc_is_gone(struct usb_process *up)
34312bd3c8bSSascha Wildner {
34412bd3c8bSSascha Wildner if (up->up_gone)
34512bd3c8bSSascha Wildner return (1);
34612bd3c8bSSascha Wildner
34712bd3c8bSSascha Wildner /*
34812bd3c8bSSascha Wildner * Allow calls when up_mtx is NULL, before the USB process
34912bd3c8bSSascha Wildner * structure is initialised.
35012bd3c8bSSascha Wildner */
351722d05c3SSascha Wildner if (up->up_lock != NULL)
3523a76bbe8SSascha Wildner KKASSERT(lockowned(up->up_lock));
35312bd3c8bSSascha Wildner return (0);
35412bd3c8bSSascha Wildner }
35512bd3c8bSSascha Wildner
35612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
35712bd3c8bSSascha Wildner * usb_proc_mwait
35812bd3c8bSSascha Wildner *
35912bd3c8bSSascha Wildner * This function will return when the USB process message pointed to
36012bd3c8bSSascha Wildner * by "pm" is no longer on a queue. This function must be called
36112bd3c8bSSascha Wildner * having "up->up_mtx" locked.
36212bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
36312bd3c8bSSascha Wildner void
usb_proc_mwait(struct usb_process * up,void * _pm0,void * _pm1)36412bd3c8bSSascha Wildner usb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
36512bd3c8bSSascha Wildner {
36612bd3c8bSSascha Wildner struct usb_proc_msg *pm0 = _pm0;
36712bd3c8bSSascha Wildner struct usb_proc_msg *pm1 = _pm1;
36812bd3c8bSSascha Wildner
36912bd3c8bSSascha Wildner /* check if gone */
37012bd3c8bSSascha Wildner if (up->up_gone)
37112bd3c8bSSascha Wildner return;
37212bd3c8bSSascha Wildner
3733a76bbe8SSascha Wildner KKASSERT(lockowned(up->up_lock));
37412bd3c8bSSascha Wildner
37512bd3c8bSSascha Wildner if (up->up_curtd == curthread) {
37612bd3c8bSSascha Wildner /* Just remove the messages from the queue. */
37712bd3c8bSSascha Wildner if (pm0->pm_qentry.tqe_prev) {
37812bd3c8bSSascha Wildner TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
37912bd3c8bSSascha Wildner pm0->pm_qentry.tqe_prev = NULL;
38012bd3c8bSSascha Wildner }
38112bd3c8bSSascha Wildner if (pm1->pm_qentry.tqe_prev) {
38212bd3c8bSSascha Wildner TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
38312bd3c8bSSascha Wildner pm1->pm_qentry.tqe_prev = NULL;
38412bd3c8bSSascha Wildner }
38512bd3c8bSSascha Wildner } else
38612bd3c8bSSascha Wildner while (pm0->pm_qentry.tqe_prev ||
38712bd3c8bSSascha Wildner pm1->pm_qentry.tqe_prev) {
38812bd3c8bSSascha Wildner /* check if config thread is gone */
38912bd3c8bSSascha Wildner if (up->up_gone)
39012bd3c8bSSascha Wildner break;
39112bd3c8bSSascha Wildner up->up_dsleep = 1;
392722d05c3SSascha Wildner cv_wait(&up->up_drain, up->up_lock);
39312bd3c8bSSascha Wildner }
39412bd3c8bSSascha Wildner }
39512bd3c8bSSascha Wildner
39612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
39712bd3c8bSSascha Wildner * usb_proc_drain
39812bd3c8bSSascha Wildner *
39912bd3c8bSSascha Wildner * This function will tear down an USB process, waiting for the
40012bd3c8bSSascha Wildner * currently executing command to return.
40112bd3c8bSSascha Wildner *
40212bd3c8bSSascha Wildner * NOTE: If the structure pointed to by "up" is all zero,
40312bd3c8bSSascha Wildner * this function does nothing.
40412bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
40512bd3c8bSSascha Wildner void
usb_proc_drain(struct usb_process * up)40612bd3c8bSSascha Wildner usb_proc_drain(struct usb_process *up)
40712bd3c8bSSascha Wildner {
40812bd3c8bSSascha Wildner /* check if not initialised */
409722d05c3SSascha Wildner if (up->up_lock == NULL)
41012bd3c8bSSascha Wildner return;
41163da4a34SSascha Wildner #if 0 /* XXX */
41212bd3c8bSSascha Wildner /* handle special case with Giant */
41312bd3c8bSSascha Wildner if (up->up_mtx != &Giant)
41412bd3c8bSSascha Wildner mtx_assert(up->up_mtx, MA_NOTOWNED);
41563da4a34SSascha Wildner #else
4163a76bbe8SSascha Wildner KKASSERT(!lockowned(up->up_lock));
417722d05c3SSascha Wildner lockmgr(up->up_lock, LK_EXCLUSIVE);
41863da4a34SSascha Wildner #endif
41912bd3c8bSSascha Wildner
42012bd3c8bSSascha Wildner /* Set the gone flag */
42112bd3c8bSSascha Wildner
42212bd3c8bSSascha Wildner up->up_gone = 1;
42312bd3c8bSSascha Wildner
42412bd3c8bSSascha Wildner while (up->up_ptr) {
42512bd3c8bSSascha Wildner
42612bd3c8bSSascha Wildner /* Check if we need to wakeup the USB process */
42712bd3c8bSSascha Wildner
42812bd3c8bSSascha Wildner if (up->up_msleep || up->up_csleep) {
42912bd3c8bSSascha Wildner up->up_msleep = 0;
43012bd3c8bSSascha Wildner up->up_csleep = 0;
43112bd3c8bSSascha Wildner cv_signal(&up->up_cv);
43212bd3c8bSSascha Wildner }
43312bd3c8bSSascha Wildner /* Check if we are still cold booted */
43412bd3c8bSSascha Wildner
43512bd3c8bSSascha Wildner if (cold) {
43612bd3c8bSSascha Wildner USB_THREAD_SUSPEND(up->up_ptr);
437722d05c3SSascha Wildner kprintf("WARNING: A USB process has "
43812bd3c8bSSascha Wildner "been left suspended\n");
43912bd3c8bSSascha Wildner break;
44012bd3c8bSSascha Wildner }
441722d05c3SSascha Wildner cv_wait(&up->up_cv, up->up_lock);
44212bd3c8bSSascha Wildner }
44312bd3c8bSSascha Wildner /* Check if someone is waiting - should not happen */
44412bd3c8bSSascha Wildner
44512bd3c8bSSascha Wildner if (up->up_dsleep) {
44612bd3c8bSSascha Wildner up->up_dsleep = 0;
44712bd3c8bSSascha Wildner cv_broadcast(&up->up_drain);
44812bd3c8bSSascha Wildner DPRINTF("WARNING: Someone is waiting "
44912bd3c8bSSascha Wildner "for USB process drain!\n");
45012bd3c8bSSascha Wildner }
451722d05c3SSascha Wildner lockmgr(up->up_lock, LK_RELEASE);
45212bd3c8bSSascha Wildner }
45312bd3c8bSSascha Wildner
45412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
45512bd3c8bSSascha Wildner * usb_proc_rewakeup
45612bd3c8bSSascha Wildner *
45712bd3c8bSSascha Wildner * This function is called to re-wakeup the given USB
45812bd3c8bSSascha Wildner * process. This usually happens after that the USB system has been in
45912bd3c8bSSascha Wildner * polling mode, like during a panic. This function must be called
460722d05c3SSascha Wildner * having "up->up_lock" locked.
46112bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
46212bd3c8bSSascha Wildner void
usb_proc_rewakeup(struct usb_process * up)46312bd3c8bSSascha Wildner usb_proc_rewakeup(struct usb_process *up)
46412bd3c8bSSascha Wildner {
46512bd3c8bSSascha Wildner /* check if not initialised */
466722d05c3SSascha Wildner if (up->up_lock == NULL)
46712bd3c8bSSascha Wildner return;
46812bd3c8bSSascha Wildner /* check if gone */
46912bd3c8bSSascha Wildner if (up->up_gone)
47012bd3c8bSSascha Wildner return;
47163da4a34SSascha Wildner
4723a76bbe8SSascha Wildner KKASSERT(lockowned(up->up_lock));
47312bd3c8bSSascha Wildner
47412bd3c8bSSascha Wildner if (up->up_msleep == 0) {
47512bd3c8bSSascha Wildner /* re-wakeup */
47612bd3c8bSSascha Wildner cv_signal(&up->up_cv);
47712bd3c8bSSascha Wildner }
47812bd3c8bSSascha Wildner }
479141a761fSMarkus Pfeiffer
480141a761fSMarkus Pfeiffer /*------------------------------------------------------------------------*
481141a761fSMarkus Pfeiffer * usb_proc_is_called_from
482141a761fSMarkus Pfeiffer *
483141a761fSMarkus Pfeiffer * This function will return non-zero if called from inside the USB
484141a761fSMarkus Pfeiffer * process passed as first argument. Else this function returns zero.
485141a761fSMarkus Pfeiffer *------------------------------------------------------------------------*/
486141a761fSMarkus Pfeiffer int
usb_proc_is_called_from(struct usb_process * up)487141a761fSMarkus Pfeiffer usb_proc_is_called_from(struct usb_process *up)
488141a761fSMarkus Pfeiffer {
489141a761fSMarkus Pfeiffer return (up->up_curtd == curthread);
490141a761fSMarkus Pfeiffer }
491