2 * Copyright (C) 2003-2008 Takahiro Hirofuchi
3 * Copyright (C) 2015 Nobuo Iwata
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 #include <linux/kthread.h>
22 #include <linux/export.h>
23 #include <linux/slab.h>
24 #include <linux/workqueue.h>
26 #include "usbip_common.h"
29 struct list_head node
;
30 struct usbip_device
*ud
;
33 static DEFINE_SPINLOCK(event_lock
);
34 static LIST_HEAD(event_list
);
36 static void set_event(struct usbip_device
*ud
, unsigned long event
)
40 spin_lock_irqsave(&ud
->lock
, flags
);
42 spin_unlock_irqrestore(&ud
->lock
, flags
);
45 static void unset_event(struct usbip_device
*ud
, unsigned long event
)
49 spin_lock_irqsave(&ud
->lock
, flags
);
51 spin_unlock_irqrestore(&ud
->lock
, flags
);
54 static struct usbip_device
*get_event(void)
56 struct usbip_event
*ue
= NULL
;
57 struct usbip_device
*ud
= NULL
;
60 spin_lock_irqsave(&event_lock
, flags
);
61 if (!list_empty(&event_list
)) {
62 ue
= list_first_entry(&event_list
, struct usbip_event
, node
);
65 spin_unlock_irqrestore(&event_lock
, flags
);
74 static struct task_struct
*worker_context
;
76 static void event_handler(struct work_struct
*work
)
78 struct usbip_device
*ud
;
80 if (worker_context
== NULL
) {
81 worker_context
= current
;
84 while ((ud
= get_event()) != NULL
) {
85 usbip_dbg_eh("pending event %lx\n", ud
->event
);
88 * NOTE: shutdown must come first.
89 * Shutdown the device.
91 if (ud
->event
& USBIP_EH_SHUTDOWN
) {
92 ud
->eh_ops
.shutdown(ud
);
93 unset_event(ud
, USBIP_EH_SHUTDOWN
);
96 /* Reset the device. */
97 if (ud
->event
& USBIP_EH_RESET
) {
99 unset_event(ud
, USBIP_EH_RESET
);
102 /* Mark the device as unusable. */
103 if (ud
->event
& USBIP_EH_UNUSABLE
) {
104 ud
->eh_ops
.unusable(ud
);
105 unset_event(ud
, USBIP_EH_UNUSABLE
);
108 /* Stop the error handler. */
109 if (ud
->event
& USBIP_EH_BYE
)
110 usbip_dbg_eh("removed %p\n", ud
);
112 wake_up(&ud
->eh_waitq
);
116 int usbip_start_eh(struct usbip_device
*ud
)
118 init_waitqueue_head(&ud
->eh_waitq
);
122 EXPORT_SYMBOL_GPL(usbip_start_eh
);
124 void usbip_stop_eh(struct usbip_device
*ud
)
126 unsigned long pending
= ud
->event
& ~USBIP_EH_BYE
;
128 if (!(ud
->event
& USBIP_EH_BYE
))
129 usbip_dbg_eh("usbip_eh stopping but not removed\n");
132 usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending
);
134 wait_event_interruptible(ud
->eh_waitq
, !(ud
->event
& ~USBIP_EH_BYE
));
135 usbip_dbg_eh("usbip_eh has stopped\n");
137 EXPORT_SYMBOL_GPL(usbip_stop_eh
);
139 #define WORK_QUEUE_NAME "usbip_event"
141 static struct workqueue_struct
*usbip_queue
;
142 static DECLARE_WORK(usbip_work
, event_handler
);
144 int usbip_init_eh(void)
146 usbip_queue
= create_singlethread_workqueue(WORK_QUEUE_NAME
);
147 if (usbip_queue
== NULL
) {
148 pr_err("failed to create usbip_event\n");
154 void usbip_finish_eh(void)
156 flush_workqueue(usbip_queue
);
157 destroy_workqueue(usbip_queue
);
161 void usbip_event_add(struct usbip_device
*ud
, unsigned long event
)
163 struct usbip_event
*ue
;
166 if (ud
->event
& USBIP_EH_BYE
)
169 set_event(ud
, event
);
171 spin_lock_irqsave(&event_lock
, flags
);
173 list_for_each_entry_reverse(ue
, &event_list
, node
) {
178 ue
= kmalloc(sizeof(struct usbip_event
), GFP_ATOMIC
);
184 list_add_tail(&ue
->node
, &event_list
);
185 queue_work(usbip_queue
, &usbip_work
);
188 spin_unlock_irqrestore(&event_lock
, flags
);
190 EXPORT_SYMBOL_GPL(usbip_event_add
);
192 int usbip_event_happened(struct usbip_device
*ud
)
197 spin_lock_irqsave(&ud
->lock
, flags
);
200 spin_unlock_irqrestore(&ud
->lock
, flags
);
204 EXPORT_SYMBOL_GPL(usbip_event_happened
);
206 int usbip_in_eh(struct task_struct
*task
)
208 if (task
== worker_context
)
213 EXPORT_SYMBOL_GPL(usbip_in_eh
);