source: rtems-libbsd/freebsd/sys/dev/usb/usb_process.c @ 165dd8e

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 165dd8e was 165dd8e, checked in by Sebastian Huber <sebastian.huber@…>, on 04/08/15 at 13:37:49

Update to FreeBSD Stable/9 2015-04-08

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