196c27377SValentina Manea /* 296c27377SValentina Manea * Copyright (C) 2003-2008 Takahiro Hirofuchi 396c27377SValentina Manea * 496c27377SValentina Manea * This is free software; you can redistribute it and/or modify 596c27377SValentina Manea * it under the terms of the GNU General Public License as published by 696c27377SValentina Manea * the Free Software Foundation; either version 2 of the License, or 796c27377SValentina Manea * (at your option) any later version. 896c27377SValentina Manea * 996c27377SValentina Manea * This is distributed in the hope that it will be useful, 1096c27377SValentina Manea * but WITHOUT ANY WARRANTY; without even the implied warranty of 1196c27377SValentina Manea * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1296c27377SValentina Manea * GNU General Public License for more details. 1396c27377SValentina Manea * 1496c27377SValentina Manea * You should have received a copy of the GNU General Public License 1596c27377SValentina Manea * along with this program; if not, write to the Free Software 1696c27377SValentina Manea * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 1796c27377SValentina Manea * USA. 1896c27377SValentina Manea */ 1996c27377SValentina Manea 2096c27377SValentina Manea #include <linux/kthread.h> 2196c27377SValentina Manea #include <linux/export.h> 2296c27377SValentina Manea 2396c27377SValentina Manea #include "usbip_common.h" 2496c27377SValentina Manea 2596c27377SValentina Manea static int event_handler(struct usbip_device *ud) 2696c27377SValentina Manea { 2796c27377SValentina Manea usbip_dbg_eh("enter\n"); 2896c27377SValentina Manea 2996c27377SValentina Manea /* 3096c27377SValentina Manea * Events are handled by only this thread. 3196c27377SValentina Manea */ 3296c27377SValentina Manea while (usbip_event_happened(ud)) { 3396c27377SValentina Manea usbip_dbg_eh("pending event %lx\n", ud->event); 3496c27377SValentina Manea 3596c27377SValentina Manea /* 3696c27377SValentina Manea * NOTE: shutdown must come first. 3796c27377SValentina Manea * Shutdown the device. 3896c27377SValentina Manea */ 3996c27377SValentina Manea if (ud->event & USBIP_EH_SHUTDOWN) { 4096c27377SValentina Manea ud->eh_ops.shutdown(ud); 4196c27377SValentina Manea ud->event &= ~USBIP_EH_SHUTDOWN; 4296c27377SValentina Manea } 4396c27377SValentina Manea 4496c27377SValentina Manea /* Reset the device. */ 4596c27377SValentina Manea if (ud->event & USBIP_EH_RESET) { 4696c27377SValentina Manea ud->eh_ops.reset(ud); 4796c27377SValentina Manea ud->event &= ~USBIP_EH_RESET; 4896c27377SValentina Manea } 4996c27377SValentina Manea 5096c27377SValentina Manea /* Mark the device as unusable. */ 5196c27377SValentina Manea if (ud->event & USBIP_EH_UNUSABLE) { 5296c27377SValentina Manea ud->eh_ops.unusable(ud); 5396c27377SValentina Manea ud->event &= ~USBIP_EH_UNUSABLE; 5496c27377SValentina Manea } 5596c27377SValentina Manea 5696c27377SValentina Manea /* Stop the error handler. */ 5796c27377SValentina Manea if (ud->event & USBIP_EH_BYE) 5896c27377SValentina Manea return -1; 5996c27377SValentina Manea } 6096c27377SValentina Manea 6196c27377SValentina Manea return 0; 6296c27377SValentina Manea } 6396c27377SValentina Manea 6496c27377SValentina Manea static int event_handler_loop(void *data) 6596c27377SValentina Manea { 6696c27377SValentina Manea struct usbip_device *ud = data; 6796c27377SValentina Manea 6896c27377SValentina Manea while (!kthread_should_stop()) { 6996c27377SValentina Manea wait_event_interruptible(ud->eh_waitq, 7096c27377SValentina Manea usbip_event_happened(ud) || 7196c27377SValentina Manea kthread_should_stop()); 7296c27377SValentina Manea usbip_dbg_eh("wakeup\n"); 7396c27377SValentina Manea 7496c27377SValentina Manea if (event_handler(ud) < 0) 7596c27377SValentina Manea break; 7696c27377SValentina Manea } 7796c27377SValentina Manea 7896c27377SValentina Manea return 0; 7996c27377SValentina Manea } 8096c27377SValentina Manea 8196c27377SValentina Manea int usbip_start_eh(struct usbip_device *ud) 8296c27377SValentina Manea { 8396c27377SValentina Manea init_waitqueue_head(&ud->eh_waitq); 8496c27377SValentina Manea ud->event = 0; 8596c27377SValentina Manea 8696c27377SValentina Manea ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh"); 8796c27377SValentina Manea if (IS_ERR(ud->eh)) { 8896c27377SValentina Manea pr_warn("Unable to start control thread\n"); 8996c27377SValentina Manea return PTR_ERR(ud->eh); 9096c27377SValentina Manea } 9196c27377SValentina Manea 9296c27377SValentina Manea return 0; 9396c27377SValentina Manea } 9496c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_start_eh); 9596c27377SValentina Manea 9696c27377SValentina Manea void usbip_stop_eh(struct usbip_device *ud) 9796c27377SValentina Manea { 9896c27377SValentina Manea if (ud->eh == current) 9996c27377SValentina Manea return; /* do not wait for myself */ 10096c27377SValentina Manea 10196c27377SValentina Manea kthread_stop(ud->eh); 10296c27377SValentina Manea usbip_dbg_eh("usbip_eh has finished\n"); 10396c27377SValentina Manea } 10496c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_stop_eh); 10596c27377SValentina Manea 10696c27377SValentina Manea void usbip_event_add(struct usbip_device *ud, unsigned long event) 10796c27377SValentina Manea { 10896c27377SValentina Manea unsigned long flags; 10996c27377SValentina Manea 11096c27377SValentina Manea spin_lock_irqsave(&ud->lock, flags); 11196c27377SValentina Manea ud->event |= event; 11296c27377SValentina Manea wake_up(&ud->eh_waitq); 11396c27377SValentina Manea spin_unlock_irqrestore(&ud->lock, flags); 11496c27377SValentina Manea } 11596c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_add); 11696c27377SValentina Manea 11796c27377SValentina Manea int usbip_event_happened(struct usbip_device *ud) 11896c27377SValentina Manea { 11996c27377SValentina Manea int happened = 0; 120*21619792SAndrew Goodbody unsigned long flags; 12196c27377SValentina Manea 122*21619792SAndrew Goodbody spin_lock_irqsave(&ud->lock, flags); 12396c27377SValentina Manea if (ud->event != 0) 12496c27377SValentina Manea happened = 1; 125*21619792SAndrew Goodbody spin_unlock_irqrestore(&ud->lock, flags); 12696c27377SValentina Manea 12796c27377SValentina Manea return happened; 12896c27377SValentina Manea } 12996c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_happened); 130