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