Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2003-2008 Takahiro Hirofuchi
0004  * Copyright (C) 2015 Nobuo Iwata
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          * NOTE: shutdown must come first.
0076          * Shutdown the device.
0077          */
0078         if (ud->event & USBIP_EH_SHUTDOWN) {
0079             ud->eh_ops.shutdown(ud);
0080             unset_event(ud, USBIP_EH_SHUTDOWN);
0081         }
0082 
0083         /* Reset the device. */
0084         if (ud->event & USBIP_EH_RESET) {
0085             ud->eh_ops.reset(ud);
0086             unset_event(ud, USBIP_EH_RESET);
0087         }
0088 
0089         /* Mark the device as unusable. */
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);