0001
0002
0003
0004
0005
0006
0007 #include <linux/kthread.h>
0008 #include <linux/export.h>
0009 #include <linux/slab.h>
0010 #include <linux/workqueue.h>
0011
0012 #include "usbip_common.h"
0013
0014 struct usbip_event {
0015 struct list_head node;
0016 struct usbip_device *ud;
0017 };
0018
0019 static DEFINE_SPINLOCK(event_lock);
0020 static LIST_HEAD(event_list);
0021
0022 static void set_event(struct usbip_device *ud, unsigned long event)
0023 {
0024 unsigned long flags;
0025
0026 spin_lock_irqsave(&ud->lock, flags);
0027 ud->event |= event;
0028 spin_unlock_irqrestore(&ud->lock, flags);
0029 }
0030
0031 static void unset_event(struct usbip_device *ud, unsigned long event)
0032 {
0033 unsigned long flags;
0034
0035 spin_lock_irqsave(&ud->lock, flags);
0036 ud->event &= ~event;
0037 spin_unlock_irqrestore(&ud->lock, flags);
0038 }
0039
0040 static struct usbip_device *get_event(void)
0041 {
0042 struct usbip_event *ue = NULL;
0043 struct usbip_device *ud = NULL;
0044 unsigned long flags;
0045
0046 spin_lock_irqsave(&event_lock, flags);
0047 if (!list_empty(&event_list)) {
0048 ue = list_first_entry(&event_list, struct usbip_event, node);
0049 list_del(&ue->node);
0050 }
0051 spin_unlock_irqrestore(&event_lock, flags);
0052
0053 if (ue) {
0054 ud = ue->ud;
0055 kfree(ue);
0056 }
0057 return ud;
0058 }
0059
0060 static struct task_struct *worker_context;
0061
0062 static void event_handler(struct work_struct *work)
0063 {
0064 struct usbip_device *ud;
0065
0066 if (worker_context == NULL) {
0067 worker_context = current;
0068 }
0069
0070 while ((ud = get_event()) != NULL) {
0071 usbip_dbg_eh("pending event %lx\n", ud->event);
0072
0073 mutex_lock(&ud->sysfs_lock);
0074
0075
0076
0077
0078 if (ud->event & USBIP_EH_SHUTDOWN) {
0079 ud->eh_ops.shutdown(ud);
0080 unset_event(ud, USBIP_EH_SHUTDOWN);
0081 }
0082
0083
0084 if (ud->event & USBIP_EH_RESET) {
0085 ud->eh_ops.reset(ud);
0086 unset_event(ud, USBIP_EH_RESET);
0087 }
0088
0089
0090 if (ud->event & USBIP_EH_UNUSABLE) {
0091 ud->eh_ops.unusable(ud);
0092 unset_event(ud, USBIP_EH_UNUSABLE);
0093 }
0094 mutex_unlock(&ud->sysfs_lock);
0095
0096 wake_up(&ud->eh_waitq);
0097 }
0098 }
0099
0100 int usbip_start_eh(struct usbip_device *ud)
0101 {
0102 init_waitqueue_head(&ud->eh_waitq);
0103 ud->event = 0;
0104 return 0;
0105 }
0106 EXPORT_SYMBOL_GPL(usbip_start_eh);
0107
0108 void usbip_stop_eh(struct usbip_device *ud)
0109 {
0110 unsigned long pending = ud->event & ~USBIP_EH_BYE;
0111
0112 if (!(ud->event & USBIP_EH_BYE))
0113 usbip_dbg_eh("usbip_eh stopping but not removed\n");
0114
0115 if (pending)
0116 usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending);
0117
0118 wait_event_interruptible(ud->eh_waitq, !(ud->event & ~USBIP_EH_BYE));
0119 usbip_dbg_eh("usbip_eh has stopped\n");
0120 }
0121 EXPORT_SYMBOL_GPL(usbip_stop_eh);
0122
0123 #define WORK_QUEUE_NAME "usbip_event"
0124
0125 static struct workqueue_struct *usbip_queue;
0126 static DECLARE_WORK(usbip_work, event_handler);
0127
0128 int usbip_init_eh(void)
0129 {
0130 usbip_queue = create_singlethread_workqueue(WORK_QUEUE_NAME);
0131 if (usbip_queue == NULL) {
0132 pr_err("failed to create usbip_event\n");
0133 return -ENOMEM;
0134 }
0135 return 0;
0136 }
0137
0138 void usbip_finish_eh(void)
0139 {
0140 destroy_workqueue(usbip_queue);
0141 usbip_queue = NULL;
0142 }
0143
0144 void usbip_event_add(struct usbip_device *ud, unsigned long event)
0145 {
0146 struct usbip_event *ue;
0147 unsigned long flags;
0148
0149 if (ud->event & USBIP_EH_BYE)
0150 return;
0151
0152 set_event(ud, event);
0153
0154 spin_lock_irqsave(&event_lock, flags);
0155
0156 list_for_each_entry_reverse(ue, &event_list, node) {
0157 if (ue->ud == ud)
0158 goto out;
0159 }
0160
0161 ue = kmalloc(sizeof(struct usbip_event), GFP_ATOMIC);
0162 if (ue == NULL)
0163 goto out;
0164
0165 ue->ud = ud;
0166
0167 list_add_tail(&ue->node, &event_list);
0168 queue_work(usbip_queue, &usbip_work);
0169
0170 out:
0171 spin_unlock_irqrestore(&event_lock, flags);
0172 }
0173 EXPORT_SYMBOL_GPL(usbip_event_add);
0174
0175 int usbip_event_happened(struct usbip_device *ud)
0176 {
0177 int happened = 0;
0178 unsigned long flags;
0179
0180 spin_lock_irqsave(&ud->lock, flags);
0181 if (ud->event != 0)
0182 happened = 1;
0183 spin_unlock_irqrestore(&ud->lock, flags);
0184
0185 return happened;
0186 }
0187 EXPORT_SYMBOL_GPL(usbip_event_happened);
0188
0189 int usbip_in_eh(struct task_struct *task)
0190 {
0191 if (task == worker_context)
0192 return 1;
0193
0194 return 0;
0195 }
0196 EXPORT_SYMBOL_GPL(usbip_in_eh);