The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/usb_process.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 8c84601258b3f72f32d0ce4c46d98e56


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.