104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Copyright (C) 2003-2008 Takahiro Hirofuchi 304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * This is free software; you can redistribute it and/or modify 504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * it under the terms of the GNU General Public License as published by 604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * the Free Software Foundation; either version 2 of the License, or 704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * (at your option) any later version. 804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * This is distributed in the hope that it will be useful, 1004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * but WITHOUT ANY WARRANTY; without even the implied warranty of 1104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * GNU General Public License for more details. 1304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 1404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * You should have received a copy of the GNU General Public License 1504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * along with this program; if not, write to the Free Software 1604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 1704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * USA. 1804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 1904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 207aaacb43ed97714ff0f7f77f306f24b6e564ad03matt mooney#include <linux/init.h> 217aaacb43ed97714ff0f7f77f306f24b6e564ad03matt mooney#include <linux/kernel.h> 229720b4bc76a83807c68e00c62bfba575251bb73eArnd Bergmann#include <linux/kthread.h> 237aaacb43ed97714ff0f7f77f306f24b6e564ad03matt mooney#include <linux/module.h> 247aaacb43ed97714ff0f7f77f306f24b6e564ad03matt mooney#include <linux/platform_device.h> 257aaacb43ed97714ff0f7f77f306f24b6e564ad03matt mooney#include <linux/slab.h> 2604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 2704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#include "usbip_common.h" 2804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#include "vhci.h" 2904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 3004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#define DRIVER_AUTHOR "Takahiro Hirofuchi" 3164e62426f40d1017a7ced93ee71d333529196365matt mooney#define DRIVER_DESC "USB/IP 'Virtual' Host Controller (VHCI) Driver" 3204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 3304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 3404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * TODO 3504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - update root hub emulation 3604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - move the emulation code to userland ? 3704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * porting to other operating systems 3804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * minimize kernel code 3904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - add suspend/resume code 4004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - clean up everything 4104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 4204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 4304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* See usb gadget dummy hcd */ 4404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 4504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hub_status(struct usb_hcd *hcd, char *buff); 4604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 47071d1d47046a275c196b3345c2d19af3c8128608matt mooney u16 wIndex, char *buff, u16 wLength); 4804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, 49071d1d47046a275c196b3345c2d19af3c8128608matt mooney gfp_t mem_flags); 5004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); 5104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_start(struct usb_hcd *vhci_hcd); 5204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_stop(struct usb_hcd *hcd); 5304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_get_frame_number(struct usb_hcd *hcd); 5404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 5504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic const char driver_name[] = "vhci_hcd"; 56f5e08ca72288b9762f49778622617184180496e7Robert P. J. Daystatic const char driver_desc[] = "USB/IP Virtual Host Controller"; 5704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 5804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistruct vhci_hcd *the_controller; 5904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 60071d1d47046a275c196b3345c2d19af3c8128608matt mooneystatic const char * const bit_desc[] = { 6104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "CONNECTION", /*0*/ 6204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "ENABLE", /*1*/ 6304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "SUSPEND", /*2*/ 6404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "OVER_CURRENT", /*3*/ 6504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "RESET", /*4*/ 66071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R5", /*5*/ 67071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R6", /*6*/ 68071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R7", /*7*/ 6904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "POWER", /*8*/ 7004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "LOWSPEED", /*9*/ 7104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "HIGHSPEED", /*10*/ 7204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "PORT_TEST", /*11*/ 7304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "INDICATOR", /*12*/ 74071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R13", /*13*/ 75071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R14", /*14*/ 76071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R15", /*15*/ 7704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "C_CONNECTION", /*16*/ 7804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "C_ENABLE", /*17*/ 7904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "C_SUSPEND", /*18*/ 8004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "C_OVER_CURRENT", /*19*/ 8104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "C_RESET", /*20*/ 82071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R21", /*21*/ 83071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R22", /*22*/ 84071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R23", /*23*/ 85071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R24", /*24*/ 86071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R25", /*25*/ 87071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R26", /*26*/ 88071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R27", /*27*/ 89071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R28", /*28*/ 90071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R29", /*29*/ 91071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R30", /*30*/ 92071d1d47046a275c196b3345c2d19af3c8128608matt mooney "R31", /*31*/ 9304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi}; 9404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 954a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Némethstatic void dump_port_status_diff(u32 prev_status, u32 new_status) 9604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 9704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int i = 0; 984a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh u32 bit = 1; 994a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh 1004a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh pr_debug("status prev -> new: %08x -> %08x\n", prev_status, new_status); 1014a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh while (bit) { 1024a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh u32 prev = prev_status & bit; 1034a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh u32 new = new_status & bit; 1044a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh char change; 1054a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh 1064a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh if (!prev && new) 1074a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh change = '+'; 1084a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh else if (prev && !new) 1094a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh change = '-'; 1104a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh else 1114a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh change = ' '; 1124a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh 1134a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh if (prev || new) 1144a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh pr_debug(" %c%s\n", change, bit_desc[i]); 1154a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh bit <<= 1; 1164a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh i++; 11704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 1181a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_debug("\n"); 11904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 12004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 12104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchivoid rh_port_connect(int rhport, enum usb_device_speed speed) 12204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 12304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 12404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 125b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport); 12604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 12704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&the_controller->lock, flags); 12804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 12904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION 13004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi | (1 << USB_PORT_FEAT_C_CONNECTION); 13104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 13204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (speed) { 13304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_SPEED_HIGH: 13404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED; 13504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 13604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_SPEED_LOW: 13704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED; 13804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 13904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 14004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 14104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 14204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 14304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* spin_lock(&the_controller->vdev[rhport].ud.lock); 14404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * the_controller->vdev[rhport].ud.status = VDEV_CONNECT; 14504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * spin_unlock(&the_controller->vdev[rhport].ud.lock); */ 14604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 14704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 14804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 14904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); 15004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 15104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 15204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchivoid rh_port_disconnect(int rhport) 15304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 15404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 15504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 156b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport); 15704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 15804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&the_controller->lock, flags); 15904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* stop_activity(dum, driver); */ 16004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; 16104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller->port_status[rhport] |= 16204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi (1 << USB_PORT_FEAT_C_CONNECTION); 16304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 16404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* not yet complete the disconnection 16504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * spin_lock(&vdev->ud.lock); 16604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * vdev->ud.status = VHC_ST_DISCONNECT; 16704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * spin_unlock(&vdev->ud.lock); */ 16804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 16904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 1700c9a32f0192e656daa2ff3c9149f6d71b4a1b873Max Vozeler usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); 17104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 17204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 173071d1d47046a275c196b3345c2d19af3c8128608matt mooney#define PORT_C_MASK \ 174071d1d47046a275c196b3345c2d19af3c8128608matt mooney ((USB_PORT_STAT_C_CONNECTION \ 175071d1d47046a275c196b3345c2d19af3c8128608matt mooney | USB_PORT_STAT_C_ENABLE \ 176071d1d47046a275c196b3345c2d19af3c8128608matt mooney | USB_PORT_STAT_C_SUSPEND \ 177071d1d47046a275c196b3345c2d19af3c8128608matt mooney | USB_PORT_STAT_C_OVERCURRENT \ 17804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi | USB_PORT_STAT_C_RESET) << 16) 17904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 18004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 18104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without 18204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * suspend/resume support. But, it is modified to provide multiple ports. 18304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 18404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * @buf: a bitmap to show which port status has been changed. 18504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 0: reserved or used for another purpose? 18604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 1: the status of port 0 has been changed. 18704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 2: the status of port 1 has been changed. 18804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * ... 18904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 7: the status of port 6 has been changed. 19004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 8: the status of port 7 has been changed. 19104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * ... 19204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * bit 15: the status of port 14 has been changed. 19304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 19404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * So, the maximum number of ports is 31 ( port 0 to port 30) ? 19504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 19625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * The return value is the actual transferred length in byte. If nothing has 19704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * been changed, return 0. In the case that the number of ports is less than or 19804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * equal to 6 (VHCI_NPORTS==7), return 1. 19904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 20004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 20104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hub_status(struct usb_hcd *hcd, char *buf) 20204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 20304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *vhci; 20404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 20504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int retval = 0; 20604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 20704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* the enough buffer is allocated according to USB_MAXCHILDREN */ 20804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long *event_bits = (unsigned long *) buf; 20904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rhport; 21004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int changed = 0; 21104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 21204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi *event_bits = 0; 21304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 21404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vhci = hcd_to_vhci(hcd); 21504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 21604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&vhci->lock, flags); 217541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) { 218b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh("hw accessible flag in on?\n"); 21904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto done; 22004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 22104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 22204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* check pseudo status register for each port */ 22304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { 22404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if ((vhci->port_status[rhport] & PORT_C_MASK)) { 22504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* The status of a port has been changed, */ 226b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh("port %d is changed\n", rhport); 22704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 22804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi *event_bits |= 1 << (rhport + 1); 22904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi changed = 1; 23004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 23104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 23204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 2331a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("changed %d\n", changed); 23404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 23504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (hcd->state == HC_STATE_SUSPENDED) 23604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_hcd_resume_root_hub(hcd); 23704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 23804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (changed) 23904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi retval = 1 + (VHCI_NPORTS / 8); 24004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi else 24104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi retval = 0; 24204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 24304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchidone: 24404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vhci->lock, flags); 24504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return retval; 24604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 24704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 24804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* See hub_configure in hub.c */ 24904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic inline void hub_descriptor(struct usb_hub_descriptor *desc) 25004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 25104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi memset(desc, 0, sizeof(*desc)); 25204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi desc->bDescriptorType = 0x29; 25304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi desc->bDescLength = 9; 25404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi desc->wHubCharacteristics = (__force __u16) 25504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi (__constant_cpu_to_le16(0x0001)); 25604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi desc->bNbrPorts = VHCI_NPORTS; 257dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[0] = 0xff; 258dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[1] = 0xff; 25904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 26004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 26104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 26204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi u16 wIndex, char *buf, u16 wLength) 26304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 26404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *dum; 26504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int retval = 0; 26604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 26704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rhport; 26804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 26904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi u32 prev_port_status[VHCI_NPORTS]; 27004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 271541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) 27204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return -ETIMEDOUT; 27304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 27404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 27504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * NOTE: 27604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * wIndex shows the port number and begins from 1. 27704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 278b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, 279071d1d47046a275c196b3345c2d19af3c8128608matt mooney wIndex); 28004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (wIndex > VHCI_NPORTS) 2811a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("invalid port number %d\n", wIndex); 28204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi rhport = ((__u8)(wIndex & 0x00ff)) - 1; 28304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 28404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum = hcd_to_vhci(hcd); 28504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 28604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&dum->lock, flags); 28704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 28804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* store old status and compare now and old later */ 289b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell if (usbip_dbg_flag_vhci_rh) { 2906f480bf9c3bf6c1241024c1763d12d025ff02292Márton Németh memcpy(prev_port_status, dum->port_status, 2916f480bf9c3bf6c1241024c1763d12d025ff02292Márton Németh sizeof(prev_port_status)); 29204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 29304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 29404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (typeReq) { 29504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case ClearHubFeature: 296b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" ClearHubFeature\n"); 29704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 29804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case ClearPortFeature: 29904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (wValue) { 30004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_PORT_FEAT_SUSPEND: 30104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) { 30204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 20msec signaling */ 30304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->resuming = 1; 30404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->re_timeout = 30504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi jiffies + msecs_to_jiffies(20); 30604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 30704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 30804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_PORT_FEAT_POWER: 309b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" ClearPortFeature: " 310071d1d47046a275c196b3345c2d19af3c8128608matt mooney "USB_PORT_FEAT_POWER\n"); 31104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] = 0; 31204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* dum->address = 0; */ 31304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* dum->hdev = 0; */ 31404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->resuming = 0; 31504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 31604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_PORT_FEAT_C_RESET: 317b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" ClearPortFeature: " 318071d1d47046a275c196b3345c2d19af3c8128608matt mooney "USB_PORT_FEAT_C_RESET\n"); 31904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (dum->vdev[rhport].speed) { 32004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_SPEED_HIGH: 32104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= 322071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_HIGH_SPEED; 32304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 32404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_SPEED_LOW: 32504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= 326071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_LOW_SPEED; 32704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 32804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 32904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 33004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 33104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 332b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", 333071d1d47046a275c196b3345c2d19af3c8128608matt mooney wValue); 33404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] &= ~(1 << wValue); 33549aecefcdef5a26a7fb036d4c57573f0e0e2089bmatt mooney break; 33604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 33704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 33804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case GetHubDescriptor: 339b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" GetHubDescriptor\n"); 34004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hub_descriptor((struct usb_hub_descriptor *) buf); 34104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 34204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case GetHubStatus: 343b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" GetHubStatus\n"); 34404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi *(__le32 *) buf = __constant_cpu_to_le32(0); 34504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 34604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case GetPortStatus: 347b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); 34804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (wIndex > VHCI_NPORTS || wIndex < 1) { 3491a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("invalid port number %d\n", wIndex); 35004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi retval = -EPIPE; 35104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 35204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 35304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* we do no care of resume. */ 35404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 35504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* whoever resets or resumes must GetPortStatus to 35604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * complete it!! 35704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * */ 35804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (dum->resuming && time_after(jiffies, dum->re_timeout)) { 35904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= 36087352760173082c2a774f83dc6fe826fdbf219c0matt mooney (1 << USB_PORT_FEAT_C_SUSPEND); 36104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] &= 36287352760173082c2a774f83dc6fe826fdbf219c0matt mooney ~(1 << USB_PORT_FEAT_SUSPEND); 36304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->resuming = 0; 36404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->re_timeout = 0; 36504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* if (dum->driver && dum->driver->resume) { 36604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * spin_unlock (&dum->lock); 36704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * dum->driver->resume (&dum->gadget); 36804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * spin_lock (&dum->lock); 36904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * } */ 37004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 37104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 37204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) != 373071d1d47046a275c196b3345c2d19af3c8128608matt mooney 0 && time_after(jiffies, dum->re_timeout)) { 37404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= 375071d1d47046a275c196b3345c2d19af3c8128608matt mooney (1 << USB_PORT_FEAT_C_RESET); 37604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] &= 377071d1d47046a275c196b3345c2d19af3c8128608matt mooney ~(1 << USB_PORT_FEAT_RESET); 37804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->re_timeout = 0; 37904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 38004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (dum->vdev[rhport].ud.status == 381071d1d47046a275c196b3345c2d19af3c8128608matt mooney VDEV_ST_NOTASSIGNED) { 382b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" enable rhport %d " 383071d1d47046a275c196b3345c2d19af3c8128608matt mooney "(status %u)\n", 384071d1d47046a275c196b3345c2d19af3c8128608matt mooney rhport, 385071d1d47046a275c196b3345c2d19af3c8128608matt mooney dum->vdev[rhport].ud.status); 38604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= 387071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_ENABLE; 38804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 38904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 39004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); 391071d1d47046a275c196b3345c2d19af3c8128608matt mooney ((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16); 39204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 393b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0], 394071d1d47046a275c196b3345c2d19af3c8128608matt mooney ((u16 *)buf)[1]); 39504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 39604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case SetHubFeature: 397b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" SetHubFeature\n"); 39804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi retval = -EPIPE; 39904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 40004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case SetPortFeature: 40104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (wValue) { 40204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_PORT_FEAT_SUSPEND: 403b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" SetPortFeature: " 404071d1d47046a275c196b3345c2d19af3c8128608matt mooney "USB_PORT_FEAT_SUSPEND\n"); 40504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 40604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_PORT_FEAT_RESET: 407b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" SetPortFeature: " 408071d1d47046a275c196b3345c2d19af3c8128608matt mooney "USB_PORT_FEAT_RESET\n"); 40904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* if it's already running, disconnect first */ 41004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) { 41104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] &= 412071d1d47046a275c196b3345c2d19af3c8128608matt mooney ~(USB_PORT_STAT_ENABLE | 413071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_LOW_SPEED | 414071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_HIGH_SPEED); 41504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* FIXME test that code path! */ 41604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 41704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 50msec reset signaling */ 41804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->re_timeout = jiffies + msecs_to_jiffies(50); 41904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 42004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* FALLTHROUGH */ 42104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 422b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", 423071d1d47046a275c196b3345c2d19af3c8128608matt mooney wValue); 42404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dum->port_status[rhport] |= (1 << wValue); 42549aecefcdef5a26a7fb036d4c57573f0e0e2089bmatt mooney break; 42604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 42704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi break; 42804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 42904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 4301a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("default: no such request\n"); 43104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* dev_dbg (hardware, 43204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * "hub control req%04x v%04x i%04x l%d\n", 43304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * typeReq, wValue, wIndex, wLength); */ 43404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 43504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* "protocol stall" on error */ 43604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi retval = -EPIPE; 43704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 43804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 439b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell if (usbip_dbg_flag_vhci_rh) { 4401a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_debug("port %d\n", rhport); 441bfb4ce20708156fc1d3aae8771a13acd8434118cMárton Németh /* Only dump valid port status */ 442bfb4ce20708156fc1d3aae8771a13acd8434118cMárton Németh if (rhport >= 0) { 4434a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh dump_port_status_diff(prev_port_status[rhport], 4444a3ca2bebe090b7db7c0f663d502f9319a26a1f0Márton Németh dum->port_status[rhport]); 445bfb4ce20708156fc1d3aae8771a13acd8434118cMárton Németh } 44604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 447b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_rh(" bye\n"); 44804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 44904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&dum->lock, flags); 45004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 45104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return retval; 45204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 45304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 45404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic struct vhci_device *get_vdev(struct usb_device *udev) 45504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 45604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int i; 45704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 45804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!udev) 45904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return NULL; 46004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 46104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi for (i = 0; i < VHCI_NPORTS; i++) 46204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (the_controller->vdev[i].udev == udev) 46304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return port_to_vdev(i); 46404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 46504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return NULL; 46604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 46704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 46804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_tx_urb(struct urb *urb) 46904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 47004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev = get_vdev(urb->dev); 47104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_priv *priv; 47204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flag; 47304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 47404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!vdev) { 4751a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("could not get virtual device"); 47604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* BUG(); */ 47704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return; 47804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 47904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 480b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC); 481b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell 48204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&vdev->priv_lock, flag); 48304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 48404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!priv) { 48504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_err(&urb->dev->dev, "malloc vhci_priv\n"); 48604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vdev->priv_lock, flag); 48704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); 48804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return; 48904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 49004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 49104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi priv->seqnum = atomic_inc_return(&the_controller->seqnum); 49204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (priv->seqnum == 0xffff) 4931a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney dev_info(&urb->dev->dev, "seqnum max\n"); 49404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 49504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi priv->vdev = vdev; 49604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi priv->urb = urb; 49704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 49804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi urb->hcpriv = (void *) priv; 49904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 50004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_add_tail(&priv->list, &vdev->priv_tx); 50104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 50204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi wake_up(&vdev->waitq_tx); 50304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vdev->priv_lock, flag); 50404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 50504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 50604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, 50704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi gfp_t mem_flags) 50804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 50904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct device *dev = &urb->dev->dev; 51004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int ret = 0; 51104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 5126d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler struct vhci_device *vdev; 51304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 514b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", 515071d1d47046a275c196b3345c2d19af3c8128608matt mooney hcd, urb, mem_flags); 51604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 51704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* patch to usb_sg_init() is in 2.5.60 */ 51804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); 51904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 52004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&the_controller->lock, flags); 52104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 52204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (urb->status != -EINPROGRESS) { 52304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_err(dev, "URB already unlinked!, status %d\n", urb->status); 52404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 52504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return urb->status; 52604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 52704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 52801446ef5af4e8802369bf4d257806e24345a9371Max Vozeler vdev = port_to_vdev(urb->dev->portnum-1); 5296d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler 5306d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler /* refuse enqueue for dead connection */ 5316d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler spin_lock(&vdev->ud.lock); 532071d1d47046a275c196b3345c2d19af3c8128608matt mooney if (vdev->ud.status == VDEV_ST_NULL || 533071d1d47046a275c196b3345c2d19af3c8128608matt mooney vdev->ud.status == VDEV_ST_ERROR) { 5341a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport); 5356d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler spin_unlock(&vdev->ud.lock); 5366d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler spin_unlock_irqrestore(&the_controller->lock, flags); 5376d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler return -ENODEV; 5386d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler } 5396d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler spin_unlock(&vdev->ud.lock); 5406d212153a838354078cc7d96f9bb23b7d1fd3d1bMax Vozeler 54104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = usb_hcd_link_urb_to_ep(hcd, urb); 54204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ret) 54304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto no_need_unlink; 54404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 54504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 546b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell * The enumeration process is as follows; 54704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 54804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 1. Get_Descriptor request to DevAddrs(0) EndPoint(0) 54904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * to get max packet length of default pipe 55004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 55104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 2. Set_Address request to DevAddr(0) EndPoint(0) 55204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 55304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 55404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (usb_pipedevice(urb->pipe) == 0) { 55504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi __u8 type = usb_pipetype(urb->pipe); 55604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct usb_ctrlrequest *ctrlreq = 557071d1d47046a275c196b3345c2d19af3c8128608matt mooney (struct usb_ctrlrequest *) urb->setup_packet; 55804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 55904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (type != PIPE_CONTROL || !ctrlreq) { 56004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_err(dev, "invalid request to devnum 0\n"); 561a7cd5829d8b3837755105d71f76a75cddf49003fShan Wei ret = -EINVAL; 56204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto no_need_xmit; 56304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 56404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 56504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi switch (ctrlreq->bRequest) { 56604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_REQ_SET_ADDRESS: 56704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* set_address may come when a device is reset */ 56804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_info(dev, "SetAddress Request (%d) to port %d\n", 56904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ctrlreq->wValue, vdev->rhport); 57004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 5717606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler if (vdev->udev) 5727606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler usb_put_dev(vdev->udev); 5737606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler vdev->udev = usb_get_dev(urb->dev); 57404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 57504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock(&vdev->ud.lock); 57604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.status = VDEV_ST_USED; 57704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock(&vdev->ud.lock); 57804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 57904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (urb->status == -EINPROGRESS) { 58004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* This request is successfully completed. */ 58104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* If not -EINPROGRESS, possibly unlinked. */ 58204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi urb->status = 0; 58304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 58404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 58504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto no_need_xmit; 58604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 58704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi case USB_REQ_GET_DESCRIPTOR: 58804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) 589b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("Not yet?: " 590071d1d47046a275c196b3345c2d19af3c8128608matt mooney "Get_Descriptor to device 0 " 591071d1d47046a275c196b3345c2d19af3c8128608matt mooney "(get max pipe size)\n"); 59204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 5937606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler if (vdev->udev) 5947606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler usb_put_dev(vdev->udev); 5957606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler vdev->udev = usb_get_dev(urb->dev); 59604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto out; 59704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 59804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi default: 59904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* NOT REACHED */ 60004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_err(dev, "invalid request to devnum 0 bRequest %u, " 60104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi "wValue %u\n", ctrlreq->bRequest, 60204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ctrlreq->wValue); 60304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = -EINVAL; 60404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto no_need_xmit; 60504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 60604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 60704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 60804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 60904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchiout: 61004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vhci_tx_urb(urb); 61104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 61204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 61304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 61404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 61504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchino_need_xmit: 61604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_hcd_unlink_urb_from_ep(hcd, urb); 61704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchino_need_unlink: 61804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 61904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); 620a7cd5829d8b3837755105d71f76a75cddf49003fShan Wei return ret; 62104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 62204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 62304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 62404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * vhci_rx gives back the urb after receiving the reply of the urb. If an 62504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives 62604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * back its urb. For the driver unlinking the urb, the content of the urb is 62704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * not important, but the calling to its completion handler is important; the 62804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * completion of unlinking is notified by the completion handler. 62904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 63004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 63104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * CLIENT SIDE 63204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 63304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - When vhci_hcd receives RET_SUBMIT, 63404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 63504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 1a). the urb of the pdu is not unlinking. 63604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - normal case 63704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => just give back the urb 63804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 63904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 1b). the urb of the pdu is unlinking. 64004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - usbip.ko will return a reply of the unlinking request. 64104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => give back the urb now and go to case 2b). 64204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 64304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - When vhci_hcd receives RET_UNLINK, 64404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 64504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 2a). a submit request is still pending in vhci_hcd. 64604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - urb was really pending in usbip.ko and urb_unlink_urb() was 64704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * completed there. 64804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => free a pending submit request 64904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => notify unlink completeness by giving back the urb 65004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 65104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 2b). a submit request is *not* pending in vhci_hcd. 65204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - urb was already given back to the core driver. 65304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => do not give back the urb 65404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 65504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 65604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * SERVER SIDE 65704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 65804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - When usbip receives CMD_UNLINK, 65904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 66004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 3a). the urb of the unlink request is now in submission. 66104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => do usb_unlink_urb(). 66204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => after the unlink is completed, send RET_UNLINK. 66304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 66404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - case 3b). the urb of the unlink request is not in submission. 66504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * - may be already completed or never be received 66604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * => send RET_UNLINK 66704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 66804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 66904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 67004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 67104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags; 67204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_priv *priv; 67304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev; 67404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 6751a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("dequeue a urb %p\n", urb); 67604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 67704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&the_controller->lock, flags); 67804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 67904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi priv = urb->hcpriv; 68004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!priv) { 68104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* URB was never linked! or will be soon given back by 68204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * vhci_rx. */ 68304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 68404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 68504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 68604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 68704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi { 68804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int ret = 0; 68904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = usb_hcd_check_unlink_urb(hcd, urb, status); 69004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ret) { 69104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 692b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell return ret; 69304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 69404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 69504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 69604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* send unlink request here? */ 69704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev = priv->vdev; 69804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 69904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!vdev->ud.tcp_socket) { 70004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* tcp connection is closed */ 70104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags2; 70204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 70304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&vdev->priv_lock, flags2); 70404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 7051a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("device %p seems to be disconnected\n", vdev); 70604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_del(&priv->list); 70704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi kfree(priv); 70804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi urb->hcpriv = NULL; 70904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 71004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vdev->priv_lock, flags2); 71104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 712b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell /* 713b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell * If tcp connection is alive, we have sent CMD_UNLINK. 714b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell * vhci_rx will receive RET_UNLINK and give back the URB. 715b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell * Otherwise, we give back it here. 716b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell */ 7171a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("gives back urb %p\n", urb); 718b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell 719b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usb_hcd_unlink_urb_from_ep(hcd, urb); 720b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell 721b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell spin_unlock_irqrestore(&the_controller->lock, flags); 722b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, 723071d1d47046a275c196b3345c2d19af3c8128608matt mooney urb->status); 724b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell spin_lock_irqsave(&the_controller->lock, flags); 725b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell 72604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } else { 72704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* tcp connection is alive */ 72804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unsigned long flags2; 72904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_unlink *unlink; 73004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 73104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irqsave(&vdev->priv_lock, flags2); 73204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 73304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* setup CMD_UNLINK pdu */ 73404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); 73504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!unlink) { 7361a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("malloc vhci_unlink\n"); 73704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vdev->priv_lock, flags2); 73804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 73904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); 74004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return -ENOMEM; 74104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 74204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 74304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unlink->seqnum = atomic_inc_return(&the_controller->seqnum); 74404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (unlink->seqnum == 0xffff) 7451a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("seqnum max\n"); 74604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 74704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi unlink->unlink_seqnum = priv->seqnum; 74804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 7491a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("device %p seems to be still connected\n", vdev); 75004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 75104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* send cmd_unlink and try to cancel the pending URB in the 75204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * peer */ 75304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_add_tail(&unlink->list, &vdev->unlink_tx); 75404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi wake_up(&vdev->waitq_tx); 75504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 75604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&vdev->priv_lock, flags2); 75704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 75804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 75904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irqrestore(&the_controller->lock, flags); 76004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 761b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("leave\n"); 76204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 76304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 76404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 76504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_device_unlink_cleanup(struct vhci_device *vdev) 76604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 76704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_unlink *unlink, *tmp; 76804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 76904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock(&vdev->priv_lock); 77004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 77104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { 7721a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum); 77304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_del(&unlink->list); 77404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi kfree(unlink); 77504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 77604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 77704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { 778b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler struct urb *urb; 779b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 780b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler /* give back URB of unanswered unlink request */ 7811a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum); 782b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 783b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); 784b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler if (!urb) { 7851a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("the urb (seqnum %lu) was already given back\n", 7861a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney unlink->unlink_seqnum); 787b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler list_del(&unlink->list); 788b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler kfree(unlink); 789b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler continue; 790b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler } 791b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 792b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler urb->status = -ENODEV; 793b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 794b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler spin_lock(&the_controller->lock); 795b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); 796b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler spin_unlock(&the_controller->lock); 797b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 798071d1d47046a275c196b3345c2d19af3c8128608matt mooney usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, 799071d1d47046a275c196b3345c2d19af3c8128608matt mooney urb->status); 800b92a5e23737172c52656a090977408a80d7f06d1Max Vozeler 80104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi list_del(&unlink->list); 80204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi kfree(unlink); 80304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 80404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 80504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock(&vdev->priv_lock); 80604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 80704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 80804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 80904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * The important thing is that only one context begins cleanup. 81004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * This is why error handling and cleanup become simple. 81104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * We do not want to consider race condition as possible. 81204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 81304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_shutdown_connection(struct usbip_device *ud) 81404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 81504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); 81604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 81704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* need this? see stub_dev.c */ 81804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ud->tcp_socket) { 8191a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket); 82004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); 82104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 82204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 8239720b4bc76a83807c68e00c62bfba575251bb73eArnd Bergmann /* kill threads related to this sdev, if v.c. exists */ 8248547d4cc2b616e4f1dafebe2c673fc986422b506Tobias Klauser if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx)) 825d1b2e95ab016a0c5b01748986f6ce42e9d11cab2Max Vozeler kthread_stop(vdev->ud.tcp_rx); 8268547d4cc2b616e4f1dafebe2c673fc986422b506Tobias Klauser if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx)) 827d1b2e95ab016a0c5b01748986f6ce42e9d11cab2Max Vozeler kthread_stop(vdev->ud.tcp_tx); 8289720b4bc76a83807c68e00c62bfba575251bb73eArnd Bergmann 8291a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("stop threads\n"); 83004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 83104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* active connection is closed */ 83204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (vdev->ud.tcp_socket != NULL) { 83304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi sock_release(vdev->ud.tcp_socket); 83404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.tcp_socket = NULL; 83504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 8361a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("release socket\n"); 83704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 83804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vhci_device_unlink_cleanup(vdev); 83904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 84004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 84104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * rh_port_disconnect() is a trigger of ... 84204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * usb_disable_device(): 84304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * disable all the endpoints for a USB device. 84404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * usb_disable_endpoint(): 84504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * disable endpoints. pending urbs are unlinked(dequeued). 84604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 84704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * NOTE: After calling rh_port_disconnect(), the USB device drivers of a 84804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * deteched device should release used urbs in a cleanup function(i.e. 84904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * xxx_disconnect()). Therefore, vhci_hcd does not need to release 85004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * pushed urbs and their private data in this function. 85104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 85204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * NOTE: vhci_dequeue() must be considered carefully. When shutdowning 85304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * a connection, vhci_shutdown_connection() expects vhci_dequeue() 85404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * gives back pushed urbs and frees their private data by request of 85504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * the cleanup function of a USB driver. When unlinking a urb with an 85604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * active connection, vhci_dequeue() does not give back the urb which 85704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * is actually given back by vhci_rx after receiving its return pdu. 85804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 85904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 86004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi rh_port_disconnect(vdev->rhport); 86104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 8621a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info("disconnect device\n"); 86304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 86404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 86504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 86604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_device_reset(struct usbip_device *ud) 86704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 86804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); 86904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 87004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock(&ud->lock); 87104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 87204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->speed = 0; 87304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->devid = 0; 87404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 8757606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler if (vdev->udev) 8767606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler usb_put_dev(vdev->udev); 8777606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler vdev->udev = NULL; 8787606ee8aa33287dd3e6eb44c78541b87a413a325Max Vozeler 87904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ud->tcp_socket = NULL; 88004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ud->status = VDEV_ST_NULL; 88104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 88204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock(&ud->lock); 88304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 88404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 88504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_device_unusable(struct usbip_device *ud) 88604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 88704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock(&ud->lock); 88804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ud->status = VDEV_ST_ERROR; 88904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock(&ud->lock); 89004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 89104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 89204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_device_init(struct vhci_device *vdev) 89304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 89404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi memset(vdev, 0, sizeof(*vdev)); 89504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 89604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.side = USBIP_VHCI; 89704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.status = VDEV_ST_NULL; 89804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_init(&vdev->ud.lock); 89904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 90004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi INIT_LIST_HEAD(&vdev->priv_rx); 90104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi INIT_LIST_HEAD(&vdev->priv_tx); 90204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi INIT_LIST_HEAD(&vdev->unlink_tx); 90304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi INIT_LIST_HEAD(&vdev->unlink_rx); 90404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_init(&vdev->priv_lock); 90504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 90604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi init_waitqueue_head(&vdev->waitq_tx); 90704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 90804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.eh_ops.shutdown = vhci_shutdown_connection; 90904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.eh_ops.reset = vhci_device_reset; 91004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->ud.eh_ops.unusable = vhci_device_unusable; 91104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 91204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usbip_start_eh(&vdev->ud); 91304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 91404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 91504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_start(struct usb_hcd *hcd) 91604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 91704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *vhci = hcd_to_vhci(hcd); 91804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rhport; 91904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int err = 0; 92004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 921b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("enter vhci_start\n"); 92204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 92304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* initialize private data of usb_hcd */ 92404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 92504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { 92604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev = &vhci->vdev[rhport]; 92704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vhci_device_init(vdev); 92804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi vdev->rhport = rhport; 92904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 93004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 93104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi atomic_set(&vhci->seqnum, 0); 93204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_init(&vhci->lock); 93304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 93404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd->power_budget = 0; /* no limit */ 93504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd->state = HC_STATE_RUNNING; 93604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd->uses_new_polling = 1; 93704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 93804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* vhci_hcd is now ready to be controlled through sysfs */ 93904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group); 94004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (err) { 9411a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("create sysfs files\n"); 94204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return err; 94304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 94404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 94504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 94604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 94704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 94804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void vhci_stop(struct usb_hcd *hcd) 94904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 95004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *vhci = hcd_to_vhci(hcd); 95104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rhport = 0; 95204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 953b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("stop VHCI controller\n"); 95404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 95504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 1. remove the userland interface of vhci_hcd */ 95604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); 95704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 95804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 2. shutdown all the ports of vhci_hcd */ 95904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi for (rhport = 0 ; rhport < VHCI_NPORTS; rhport++) { 96004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_device *vdev = &vhci->vdev[rhport]; 96104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 96204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); 96304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usbip_stop_eh(&vdev->ud); 96404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 96504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 96604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 96704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_get_frame_number(struct usb_hcd *hcd) 96804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 9691a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("Not yet implemented\n"); 97004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 97104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 97204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 97304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#ifdef CONFIG_PM 97404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 97504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* FIXME: suspend/resume */ 97604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_bus_suspend(struct usb_hcd *hcd) 97704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 97804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *vhci = hcd_to_vhci(hcd); 97904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 98004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); 98104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 98204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irq(&vhci->lock); 98304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* vhci->rh_state = DUMMY_RH_SUSPENDED; 98404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * set_link_state(vhci); */ 98504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd->state = HC_STATE_SUSPENDED; 98604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irq(&vhci->lock); 98704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 98804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 98904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 99004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 99104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_bus_resume(struct usb_hcd *hcd) 99204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 99304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct vhci_hcd *vhci = hcd_to_vhci(hcd); 99404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rc = 0; 99504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 99604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); 99704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 99804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock_irq(&vhci->lock); 999541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) { 100004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi rc = -ESHUTDOWN; 100104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } else { 100204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* vhci->rh_state = DUMMY_RH_RUNNING; 100304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * set_link_state(vhci); 100404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * if (!list_empty(&vhci->urbp_list)) 100504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * mod_timer(&vhci->timer, jiffies); */ 100604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd->state = HC_STATE_RUNNING; 100704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 100804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock_irq(&vhci->lock); 100904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 101087352760173082c2a774f83dc6fe826fdbf219c0matt mooney return rc; 101104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 101204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 101304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#else 101404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 101504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#define vhci_bus_suspend NULL 101604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#define vhci_bus_resume NULL 101704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#endif 101804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 101904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic struct hc_driver vhci_hc_driver = { 102004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .description = driver_name, 102104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .product_desc = driver_desc, 102204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .hcd_priv_size = sizeof(struct vhci_hcd), 102304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 102404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .flags = HCD_USB2, 102504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 102604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .start = vhci_start, 1027005126872a3a605d6f7fc2f739f5d4234f9df92cRuslan Pisarev .stop = vhci_stop, 102804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 102904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .urb_enqueue = vhci_urb_enqueue, 103004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .urb_dequeue = vhci_urb_dequeue, 103104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 103204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .get_frame_number = vhci_get_frame_number, 103304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 103404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .hub_status_data = vhci_hub_status, 103504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .hub_control = vhci_hub_control, 103604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .bus_suspend = vhci_bus_suspend, 103704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .bus_resume = vhci_bus_resume, 103804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi}; 103904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 104004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hcd_probe(struct platform_device *pdev) 104104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 104204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct usb_hcd *hcd; 104304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int ret; 104404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 1045b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); 104604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 104704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* will be removed */ 104804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (pdev->dev.dma_mask) { 104904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_info(&pdev->dev, "vhci_hcd DMA not supported\n"); 105004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return -EINVAL; 105104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 105204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 105304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 105404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Allocate and initialize hcd. 105504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Our private data is also allocated automatically. 105604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 1057e913397202b7551299da20fc8cf7b90c46f61ba3Kay Sievers hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); 105804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!hcd) { 10591a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("create hcd failed\n"); 106004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return -ENOMEM; 106104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 1062cee6a262550f53a13acfefbc1e3e5ff35c96182cAlan Stern hcd->has_tt = 1; 106304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 106404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* this is private data for vhci_hcd */ 106504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller = hcd_to_vhci(hcd); 106604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 106704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 106804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Finish generic HCD structure initialization and register. 106904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Call the driver's reset() and start() routines. 107004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 107104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = usb_add_hcd(hcd, 0, 0); 107204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ret != 0) { 10731a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_err("usb_add_hcd failed %d\n", ret); 107404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_put_hcd(hcd); 107504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller = NULL; 107604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return ret; 107704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 107804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 1079b8868e45c5f8956d57ba489df3ebd24e3f858684Brian G. Merrell usbip_dbg_vhci_hc("bye\n"); 108004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 108104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 108204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 108304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hcd_remove(struct platform_device *pdev) 108404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 108504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct usb_hcd *hcd; 108604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 108704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd = platform_get_drvdata(pdev); 108804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (!hcd) 108904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 109004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 109104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* 109204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * Disconnects the root hub, 109304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * then reverses the effects of usb_add_hcd(), 109404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * invoking the HCD's stop() methods. 109504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 109604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_remove_hcd(hcd); 109704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_put_hcd(hcd); 109804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi the_controller = NULL; 109904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 110004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 110104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 110204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 110304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#ifdef CONFIG_PM 110404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 110504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* what should happen for USB/IP under suspend/resume? */ 110604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) 110704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 110804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct usb_hcd *hcd; 110904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int rhport = 0; 111004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int connected = 0; 111104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int ret = 0; 111204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 111304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd = platform_get_drvdata(pdev); 111404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 111504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_lock(&the_controller->lock); 111604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 111704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi for (rhport = 0; rhport < VHCI_NPORTS; rhport++) 111804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (the_controller->port_status[rhport] & 1119071d1d47046a275c196b3345c2d19af3c8128608matt mooney USB_PORT_STAT_CONNECTION) 112004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi connected += 1; 112104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 112204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi spin_unlock(&the_controller->lock); 112304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 112404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (connected > 0) { 11251a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney dev_info(&pdev->dev, "We have %d active connection%s. Do not " 11261a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney "suspend.\n", connected, (connected == 1 ? "" : "s")); 112704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = -EBUSY; 112804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } else { 11291a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney dev_info(&pdev->dev, "suspend vhci_hcd"); 113004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 113104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi } 113204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 113304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return ret; 113404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 113504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 113604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic int vhci_hcd_resume(struct platform_device *pdev) 113704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 113804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi struct usb_hcd *hcd; 113904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 114004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi dev_dbg(&pdev->dev, "%s\n", __func__); 114104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 114204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi hcd = platform_get_drvdata(pdev); 114304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 114404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi usb_hcd_poll_rh_status(hcd); 114504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 114604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return 0; 114704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 114804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 114904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#else 115004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 115104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#define vhci_hcd_suspend NULL 115204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#define vhci_hcd_resume NULL 115304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 115404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi#endif 115504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 115604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic struct platform_driver vhci_driver = { 115704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .probe = vhci_hcd_probe, 115804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .remove = __devexit_p(vhci_hcd_remove), 115904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .suspend = vhci_hcd_suspend, 116004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .resume = vhci_hcd_resume, 116104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .driver = { 116204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .name = (char *) driver_name, 116304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .owner = THIS_MODULE, 116404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi }, 116504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi}; 116604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 116704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi/* 116804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * The VHCI 'device' is 'virtual'; not a real plug&play hardware. 116904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * We need to add this virtual device as a platform device arbitrarily: 117004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi * 1. platform_device_register() 117104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi */ 117204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic void the_pdev_release(struct device *dev) 117304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 117404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return; 117504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 117604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 117704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchistatic struct platform_device the_pdev = { 117804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* should be the same name as driver_name */ 117904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .name = (char *) driver_name, 118004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .id = -1, 118104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .dev = { 118204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi /* .driver = &vhci_driver, */ 118304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi .release = the_pdev_release, 118404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi }, 118504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi}; 118604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 11870392bbb6f6af31888570a24641158d9b51b07eb6matt mooneystatic int __init vhci_hcd_init(void) 118804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 118904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi int ret; 119004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 119104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (usb_disabled()) 119204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return -ENODEV; 119304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 119404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = platform_driver_register(&vhci_driver); 119504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ret < 0) 119604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto err_driver_register; 119704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 119804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi ret = platform_device_register(&the_pdev); 119904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi if (ret < 0) 120004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi goto err_platform_device_register; 120104679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 12021a4b6f66285785ddccef049e6b45be4e7c7a2189matt mooney pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); 120304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return ret; 120404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 120504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchierr_platform_device_register: 120604679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi platform_driver_unregister(&vhci_driver); 120704679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchierr_driver_register: 120804679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi return ret; 120904679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 121004679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi 12110392bbb6f6af31888570a24641158d9b51b07eb6matt mooneystatic void __exit vhci_hcd_exit(void) 121204679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi{ 121304679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi platform_device_unregister(&the_pdev); 121404679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi platform_driver_unregister(&vhci_driver); 121504679b3489e048cd5dae79e050a3afed8e4e42b6Takahiro Hirofuchi} 1216071d1d47046a275c196b3345c2d19af3c8128608matt mooney 12170392bbb6f6af31888570a24641158d9b51b07eb6matt mooneymodule_init(vhci_hcd_init); 12180392bbb6f6af31888570a24641158d9b51b07eb6matt mooneymodule_exit(vhci_hcd_exit); 1219071d1d47046a275c196b3345c2d19af3c8128608matt mooney 1220071d1d47046a275c196b3345c2d19af3c8128608matt mooneyMODULE_AUTHOR(DRIVER_AUTHOR); 1221071d1d47046a275c196b3345c2d19af3c8128608matt mooneyMODULE_DESCRIPTION(DRIVER_DESC); 12224ce0a41f1054b58801f7e14f5036cf27a75152e2matt mooneyMODULE_LICENSE("GPL"); 12236973c6f24e105f1bdf811ec2320d2de8798145eematt mooneyMODULE_VERSION(USBIP_VERSION); 1224