FreeBSD/sys/dev/usb/usb_process.c
/*------------------------------------------------------------------------*
 *	usb_process
 *
 * This function is the USB process dispatcher.
 *------------------------------------------------------------------------*/
usb_process
This function is the USB process dispatcher.
usb_process This function is the USB process dispatcher .
static void
usb_process(void *arg)
{
	struct usb_process *up = arg;
	struct usb_proc_msg *pm;
	struct thread *td;
	USB_THREAD_SUSPEND_CHECK();
	td = curthread;
	thread_lock(td);
	sched_prio(td, up->up_prio);
	thread_unlock(td);
	mtx_lock(up->up_mtx);
	up->up_curtd = td;
	while (1) {
		if (up->up_gone)
			break;
		pm = TAILQ_FIRST(&up->up_qhead);
		if (pm) {
			DPRINTF("Message pm=%p, cb=%p (enter)\n",
			    pm, pm->pm_callback);
			(pm->pm_callback) (pm);
			if (pm == TAILQ_FIRST(&up->up_qhead)) {
				TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
				pm->pm_qentry.tqe_prev = NULL;
			}
			DPRINTF("Message pm=%p (leave)\n", pm);
			continue;
		}
		if (up->up_dsleep) {
			up->up_dsleep = 0;
			cv_broadcast(&up->up_drain);
		}
		up->up_msleep = 1;
		cv_wait(&up->up_cv, up->up_mtx);
	}
	up->up_ptr = NULL;
	cv_signal(&up->up_cv);
	mtx_unlock(up->up_mtx);
#if (__FreeBSD_version >= 800000)
	if (--usb_pcount == 0)
		usbproc = NULL;
#endif
	USB_THREAD_EXIT(0);
}
static void usb_process ( void * arg ) { struct usb_process * up = arg ; struct usb_proc_msg * pm ; struct thread * td ; USB_THREAD_SUSPEND_CHECK ( ) ; td = curthread ; thread_lock ( td ) ; sched_prio ( td , up -> up_prio ) ; thread_unlock ( td ) ; mtx_lock ( up -> up_mtx ) ; up -> up_curtd = td ; while ( 1 ) { if ( up -> up_gone ) break ; pm = TAILQ_FIRST ( & up -> up_qhead ) ; if ( pm ) { DPRINTF ( " \n " , pm , pm -> pm_callback ) ; ( pm -> pm_callback ) ( pm ) ; if ( pm == TAILQ_FIRST ( & up -> up_qhead ) ) { TAILQ_REMOVE ( & up -> up_qhead , pm , pm_qentry ) ; pm -> pm_qentry . tqe_prev = NULL ; } DPRINTF ( " \n " , pm ) ; continue ; } if ( up -> up_dsleep ) { up -> up_dsleep = 0 ; cv_broadcast ( & up -> up_drain ) ; } up -> up_msleep = 1 ; cv_wait ( & up -> up_cv , up -> up_mtx ) ; } up -> up_ptr = NULL ; cv_signal ( & up -> up_cv ) ; mtx_unlock ( up -> up_mtx ) ; #if ( __FreeBSD_version >= 800000 ) if ( -- usb_pcount == 0 ) usbproc = NULL ; #endif USB_THREAD_EXIT ( 0 ) ; }
usb_process
 This function is the USB process dispatcher.
usb_process This function is the USB process dispatcher .
/* in case of attach error, check for suspended */ /* adjust priority */ /*
		 * NOTE to reimplementors: dequeueing a command from the
		 * "used" queue and executing it must be atomic, with regard
		 * to the "up_mtx" mutex. That means any attempt to queue a
		 * command by another thread must be blocked until either:
		 *
		 * 1) the command sleeps
		 *
		 * 2) the command returns
		 *
		 * Here is a practical example that shows how this helps
		 * solving a problem:
		 *
		 * Assume that you want to set the baud rate on a USB serial
		 * device. During the programming of the device you don't
		 * want to receive nor transmit any data, because it will be
		 * garbage most likely anyway. The programming of our USB
		 * device takes 20 milliseconds and it needs to call
		 * functions that sleep.
		 *
		 * Non-working solution: Before we queue the programming
		 * command, we stop transmission and reception of data. Then
		 * we queue a programming command. At the end of the
		 * programming command we enable transmission and reception
		 * of data.
		 *
		 * Problem: If a second programming command is queued while the
		 * first one is sleeping, we end up enabling transmission
		 * and reception of data too early.
		 *
		 * Working solution: Before we queue the programming command,
		 * we stop transmission and reception of data. Then we queue
		 * a programming command. Then we queue a second command
		 * that only enables transmission and reception of data.
		 *
		 * Why it works: If a second programming command is queued
		 * while the first one is sleeping, then the queueing of a
		 * second command to enable the data transfers, will cause
		 * the previous one, which is still on the queue, to be
		 * removed from the queue, and re-inserted after the last
		 * baud rate programming command, which then gives the
		 * desired result.
		 */ /* nothing changed */ /* end if messages - check if anyone is waiting for sync */ /* Clear the proc pointer if this is the last thread. */