Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2003-2008 Takahiro Hirofuchi
  3 *
  4 * This is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation; either version 2 of the License, or
  7 * (at your option) any later version.
  8 *
  9 * This is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program; if not, write to the Free Software
 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 17 * USA.
 18 */
 19
 20#include <linux/kthread.h>
 21#include <linux/export.h>
 22
 23#include "usbip_common.h"
 24
 25static int event_handler(struct usbip_device *ud)
 26{
 27	usbip_dbg_eh("enter\n");
 28
 29	/*
 30	 * Events are handled by only this thread.
 31	 */
 32	while (usbip_event_happened(ud)) {
 33		usbip_dbg_eh("pending event %lx\n", ud->event);
 34
 35		/*
 36		 * NOTE: shutdown must come first.
 37		 * Shutdown the device.
 38		 */
 39		if (ud->event & USBIP_EH_SHUTDOWN) {
 40			ud->eh_ops.shutdown(ud);
 41			ud->event &= ~USBIP_EH_SHUTDOWN;
 42		}
 43
 44		/* Reset the device. */
 45		if (ud->event & USBIP_EH_RESET) {
 46			ud->eh_ops.reset(ud);
 47			ud->event &= ~USBIP_EH_RESET;
 48		}
 49
 50		/* Mark the device as unusable. */
 51		if (ud->event & USBIP_EH_UNUSABLE) {
 52			ud->eh_ops.unusable(ud);
 53			ud->event &= ~USBIP_EH_UNUSABLE;
 54		}
 55
 56		/* Stop the error handler. */
 57		if (ud->event & USBIP_EH_BYE)
 58			return -1;
 59	}
 60
 61	return 0;
 62}
 63
 64static int event_handler_loop(void *data)
 65{
 66	struct usbip_device *ud = data;
 67
 68	while (!kthread_should_stop()) {
 69		wait_event_interruptible(ud->eh_waitq,
 70					 usbip_event_happened(ud) ||
 71					 kthread_should_stop());
 72		usbip_dbg_eh("wakeup\n");
 73
 74		if (event_handler(ud) < 0)
 75			break;
 76	}
 77
 78	return 0;
 79}
 80
 81int usbip_start_eh(struct usbip_device *ud)
 82{
 83	init_waitqueue_head(&ud->eh_waitq);
 84	ud->event = 0;
 85
 86	ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh");
 87	if (IS_ERR(ud->eh)) {
 88		pr_warn("Unable to start control thread\n");
 89		return PTR_ERR(ud->eh);
 90	}
 91
 92	return 0;
 93}
 94EXPORT_SYMBOL_GPL(usbip_start_eh);
 95
 96void usbip_stop_eh(struct usbip_device *ud)
 97{
 98	if (ud->eh == current)
 99		return; /* do not wait for myself */
100
101	kthread_stop(ud->eh);
102	usbip_dbg_eh("usbip_eh has finished\n");
103}
104EXPORT_SYMBOL_GPL(usbip_stop_eh);
105
106void usbip_event_add(struct usbip_device *ud, unsigned long event)
107{
108	unsigned long flags;
109
110	spin_lock_irqsave(&ud->lock, flags);
111	ud->event |= event;
112	wake_up(&ud->eh_waitq);
113	spin_unlock_irqrestore(&ud->lock, flags);
114}
115EXPORT_SYMBOL_GPL(usbip_event_add);
116
117int usbip_event_happened(struct usbip_device *ud)
118{
119	int happened = 0;
120	unsigned long flags;
121
122	spin_lock_irqsave(&ud->lock, flags);
123	if (ud->event != 0)
124		happened = 1;
125	spin_unlock_irqrestore(&ud->lock, flags);
126
127	return happened;
128}
129EXPORT_SYMBOL_GPL(usbip_event_happened);