1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2003-2008 Takahiro Hirofuchi
4 * Copyright (C) 2015 Nobuo Iwata
7 #include <linux/kthread.h>
8 #include <linux/export.h>
9 #include <linux/slab.h>
10 #include <linux/workqueue.h>
12 #include "usbip_common.h"
15 struct list_head node
;
16 struct usbip_device
*ud
;
19 static DEFINE_SPINLOCK(event_lock
);
20 static LIST_HEAD(event_list
);
22 static void set_event(struct usbip_device
*ud
, unsigned long event
)
26 spin_lock_irqsave(&ud
->lock
, flags
);
28 spin_unlock_irqrestore(&ud
->lock
, flags
);
31 static void unset_event(struct usbip_device
*ud
, unsigned long event
)
35 spin_lock_irqsave(&ud
->lock
, flags
);
37 spin_unlock_irqrestore(&ud
->lock
, flags
);
40 static struct usbip_device
*get_event(void)
42 struct usbip_event
*ue
= NULL
;
43 struct usbip_device
*ud
= NULL
;
46 spin_lock_irqsave(&event_lock
, flags
);
47 if (!list_empty(&event_list
)) {
48 ue
= list_first_entry(&event_list
, struct usbip_event
, node
);
51 spin_unlock_irqrestore(&event_lock
, flags
);
60 static struct task_struct
*worker_context
;
62 static void event_handler(struct work_struct
*work
)
64 struct usbip_device
*ud
;
66 if (worker_context
== NULL
) {
67 worker_context
= current
;
70 while ((ud
= get_event()) != NULL
) {
71 usbip_dbg_eh("pending event %lx\n", ud
->event
);
74 * NOTE: shutdown must come first.
75 * Shutdown the device.
77 if (ud
->event
& USBIP_EH_SHUTDOWN
) {
78 ud
->eh_ops
.shutdown(ud
);
79 unset_event(ud
, USBIP_EH_SHUTDOWN
);
82 /* Reset the device. */
83 if (ud
->event
& USBIP_EH_RESET
) {
85 unset_event(ud
, USBIP_EH_RESET
);
88 /* Mark the device as unusable. */
89 if (ud
->event
& USBIP_EH_UNUSABLE
) {
90 ud
->eh_ops
.unusable(ud
);
91 unset_event(ud
, USBIP_EH_UNUSABLE
);
94 wake_up(&ud
->eh_waitq
);
98 int usbip_start_eh(struct usbip_device
*ud
)
100 init_waitqueue_head(&ud
->eh_waitq
);
104 EXPORT_SYMBOL_GPL(usbip_start_eh
);
106 void usbip_stop_eh(struct usbip_device
*ud
)
108 unsigned long pending
= ud
->event
& ~USBIP_EH_BYE
;
110 if (!(ud
->event
& USBIP_EH_BYE
))
111 usbip_dbg_eh("usbip_eh stopping but not removed\n");
114 usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending
);
116 wait_event_interruptible(ud
->eh_waitq
, !(ud
->event
& ~USBIP_EH_BYE
));
117 usbip_dbg_eh("usbip_eh has stopped\n");
119 EXPORT_SYMBOL_GPL(usbip_stop_eh
);
121 #define WORK_QUEUE_NAME "usbip_event"
123 static struct workqueue_struct
*usbip_queue
;
124 static DECLARE_WORK(usbip_work
, event_handler
);
126 int usbip_init_eh(void)
128 usbip_queue
= create_singlethread_workqueue(WORK_QUEUE_NAME
);
129 if (usbip_queue
== NULL
) {
130 pr_err("failed to create usbip_event\n");
136 void usbip_finish_eh(void)
138 flush_workqueue(usbip_queue
);
139 destroy_workqueue(usbip_queue
);
143 void usbip_event_add(struct usbip_device
*ud
, unsigned long event
)
145 struct usbip_event
*ue
;
148 if (ud
->event
& USBIP_EH_BYE
)
151 set_event(ud
, event
);
153 spin_lock_irqsave(&event_lock
, flags
);
155 list_for_each_entry_reverse(ue
, &event_list
, node
) {
160 ue
= kmalloc(sizeof(struct usbip_event
), GFP_ATOMIC
);
166 list_add_tail(&ue
->node
, &event_list
);
167 queue_work(usbip_queue
, &usbip_work
);
170 spin_unlock_irqrestore(&event_lock
, flags
);
172 EXPORT_SYMBOL_GPL(usbip_event_add
);
174 int usbip_event_happened(struct usbip_device
*ud
)
179 spin_lock_irqsave(&ud
->lock
, flags
);
182 spin_unlock_irqrestore(&ud
->lock
, flags
);
186 EXPORT_SYMBOL_GPL(usbip_event_happened
);
188 int usbip_in_eh(struct task_struct
*task
)
190 if (task
== worker_context
)
195 EXPORT_SYMBOL_GPL(usbip_in_eh
);