dummy_hcd.c revision 0fb5759952e934dd5ff25fd79f45cb5d69c8d2d1
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintainer: Alan Stern <stern@rowland.harvard.edu> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 David Brownell 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2005 Alan Stern 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver. USB traffic is simulated; there's 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware. Use this with two other drivers: 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Gadget driver, responding to requests (slave); 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Host-side device driver, as already familiar in Linux. 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development, 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues. UML could help too. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 47d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 499454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h> 5027729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Host+Gadget Emulator" 60391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION "02 May 2005" 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ 63caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char driver_name [] = "dummy_hcd"; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char driver_desc [] = "USB Host+Gadget Emulator"; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char gadget_name [] = "dummy_udc"; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell"); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL"); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters { 741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman bool is_super_speed; 757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman bool is_high_speed; 761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}; 771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = { 797eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman .is_super_speed = false, 807eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman .is_high_speed = true, 811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}; 821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); 831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); 847eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); 857eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep { 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_io; /* jiffies timestamp */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *desc; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep ep; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned halted : 1; 96851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern unsigned wedged : 1; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned already_seen : 1; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned setup_stage : 1; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request { 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; /* ep's requests */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request req; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_ep, struct dummy_ep, ep); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_request *_req) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_req, struct dummy_request, req); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types: 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * number can be changed. Names like "ep-a" are used for this type. 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Fixed Function: in other cases. some characteristics may be mutable; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that'd be hardware-specific. Names like "ep12out-bulk" are used. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on. 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0"; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0name, /* everyone has ep0 */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* act like a net2280: high speed, six configurable endpoints */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like pxa250: fifteen fixed function endpoints */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep15in-int", 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like sa1100: two fixed function endpoints */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1out-bulk", "ep2in-bulk", 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 15052950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 153d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE 64 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 162391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state { 163391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RESET, 164391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_SUSPENDED, 165391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RUNNING 166391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}; 167391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd { 169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum; 170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman enum dummy_rh_state rh_state; 171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct timer_list timer; 172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman u32 port_status; 173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman u32 old_status; 174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned long re_timeout; 175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct usb_device *udev; 177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct list_head urbp_list; 178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned active:1; 180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned old_active:1; 181cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned resuming:1; 182cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}; 183cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE/GADGET side support 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep ep [DUMMY_ENDPOINTS]; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget gadget; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget_driver *driver; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request fifo_req; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fifo_buf [FIFO_SIZE]; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 devstatus; 197391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned udc_suspended:1; 198f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned pullup:1; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER/HOST side support 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *hs_hcd; 2041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct dummy_hcd *ss_hcd; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return (struct dummy_hcd *) (hcd->hcd_priv); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of((void *) dum, struct usb_hcd, hcd_priv); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return dummy_hcd_to_hcd(dum)->self.controller; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum) 223d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 224d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return dum->gadget.dev.parent; 225d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 226d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (ep->gadget, struct dummy, gadget); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 234cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = container_of(gadget, struct dummy, gadget); 2351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed == USB_SPEED_SUPER) 2361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dum->ss_hcd; 2371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 2381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dum->hs_hcd; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (dev, struct dummy, gadget.dev); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 246cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy the_controller; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */ 251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */ 253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep) 254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern while (!list_empty (&ep->queue)) { 256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_request *req; 257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req = list_entry (ep->queue.next, struct dummy_request, queue); 259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern list_del_init (&req->queue); 260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req->req.status = -ESHUTDOWN; 261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock (&dum->lock); 263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req->req.complete (&ep->ep, &req->req); 264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock (&dum->lock); 265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void 270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum) 271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_ep *ep; 273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* prevent any more requests */ 275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->address = 0; 276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* The timer is left running so that outstanding URBs can fail */ 278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* nuke any pending requests first, so driver i/o is quiesced */ 280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) 281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern nuke (dum, ep); 282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 283f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* driver now does any non-usb quiescing necessary */ 284f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 285f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/** 2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to 2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * the hcd speed 2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for 2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * 2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the 2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd. 2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd) 2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct dummy *dum = dum_hcd->dum; 2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) { 2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) { 3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum->pullup || dum->udc_suspended) { 3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* UDC suspend must cause a disconnect */ 3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | 3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE); 3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) != 0) 3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* device is connected and not suspended */ 3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION | 3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SPEED_5GBPS) ; 3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) == 0) 3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE) == 1 && 3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dum_hcd->port_status & 3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_LS_U0) == 1 && 3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->active = 1; 3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) { 3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum->pullup || dum->udc_suspended) { 3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* UDC suspend must cause a disconnect */ 3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | 3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE | 3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_LOW_SPEED | 3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_HIGH_SPEED | 3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SUSPEND); 3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) != 0) 3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; 3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) == 0) 3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) 3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else if ((dum_hcd->port_status & 3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SUSPEND) == 0 && 3481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 3491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->active = 1; 3501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 3531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 354f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd) 356f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 357cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 358cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 359cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->active = 0; 3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->pullup) 3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 && 3621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->gadget.speed != USB_SPEED_SUPER) || 3631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 && 3641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->gadget.speed == USB_SPEED_SUPER)) 3651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return; 3661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state_by_speed(dum_hcd); 368f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || 370cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->active) 371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 0; 372f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* if !connected or reset */ 374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || 375cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { 3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * We're connected and not reset (reset occurred now), 3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * and driver attached - disconnect! 3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && 3811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && 3821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver) { 3831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman stop_activity(dum); 3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->disconnect(&dum->gadget); 3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 387f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 388cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (dum_hcd->active != dum_hcd->old_active) { 389cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->old_active && dum->driver->suspend) { 3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->suspend(&dum->gadget); 3921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 3931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum_hcd->old_active && dum->driver->resume) { 3941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->resume(&dum->gadget); 3961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 397f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 398f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 400cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->old_status = dum_hcd->port_status; 401cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->old_active = dum_hcd->active; 402f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 403f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 404f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/ 405f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state. All the work is done when the host 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation. Real device controller 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc. 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dum->port_status & USB_PORT_STAT_ENABLE) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 420cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !desc || ep->desc || _ep->name == ep0name 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || desc->bDescriptorType != USB_DT_ENDPOINT) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum->driver) 431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return -ESHUTDOWN; 432719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior 433719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 434cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!is_enabled(dum_hcd)) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 436cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 437cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman /* 438cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the 439cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * maximum packet size. 4401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * For SS devices the wMaxPacketSize is limited by 1024. 441cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman */ 442cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* drivers must not request bad settings, since lower levels 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (hardware or its drivers) may not check. some endpoints 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't do iso, many have maxpacket limitations, etc. 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since this "hardware" driver is here to help debugging, we 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have some extra sanity checks. (there could be more though, 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * especially for "ep9out" style fixed function ones.) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso") 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) { 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 4611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (max == 1024) 4621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 4631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto done; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max == 512) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4679063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil goto done; 4689063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil case USB_SPEED_FULL: 4699063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil if (max == 8 || max == 16 || max == 32 || max == 64) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we'll fake any legal size */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4729063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil /* save a return statement */ 4739063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil default: 4749063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil goto done; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 64) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 8) 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-bulk") 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 5031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1023) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* few chips support control except on ep0 */ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->maxpacket = max; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = desc; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 524d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->name, 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bEndpointAddress & 0x0f, 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *val; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 5307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_BULK: 5317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "bulk"; 5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_ISOC: 5347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "iso"; 5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_INT: 5377c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "intr"; 5387c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5397c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman default: 5407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "ctrl"; 5417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; val; }), 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* at this point real hardware should be NAKing transfers 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to that endpoint, until a buffer is queued to it. 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 548851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->halted = ep->wedged = 0; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep) 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !ep->desc || _ep->name == ep0name) 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nuke (dum, ep); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 572d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request * 57755016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5867039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn req = kzalloc(sizeof(*req), mem_flags); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&req->queue); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &req->req; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON (!list_empty (&req->queue)); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (req); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req) 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6145db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req, 61555016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags) 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 620cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_req || !list_empty (&req->queue) || !_req->complete) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || (!ep->desc && _ep->name != ep0name)) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 632719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 633cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum->driver || !is_enabled(dum_hcd)) 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 637d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, _req, _ep->name, _req->length, _req->buf); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -EINPROGRESS; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = 0; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* implement an emulated single-request FIFO */ 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&dum->fifo_req.queue) && 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&ep->queue) && 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->length <= FIFO_SIZE) { 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = &dum->fifo_req; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req = *_req; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.buf = dum->fifo_buf; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (dum->fifo_buf, _req->buf, _req->length); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.context = dum; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete = fifo_complete; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 657c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell list_add_tail(&req->queue, &ep->queue); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = _req->length; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = 0; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 663c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell } else 664c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell list_add_tail(&req->queue, &ep->queue); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware would likely enable transfers here, in case 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it'd been left NAKing. 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = -EINVAL; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req = NULL; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !_req) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 689b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern local_irq_save (flags); 690b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern spin_lock (&dum->lock); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (&req->req == _req) { 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -ECONNRESET; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 699b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern spin_unlock (&dum->lock); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 702d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dequeued req %p from %s, len %d buf %p\n", 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req, _ep->name, _req->length, _req->buf); 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 707b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern local_irq_restore (flags); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 712851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!value) 724851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->halted = ep->wedged = 0; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !list_empty (&ep->queue)) 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 728851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern else { 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 1; 730851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern if (wedged) 731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->wedged = 1; 732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern } 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME clear emulated data toggle too */ 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int 738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value) 739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{ 740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return dummy_set_halt_and_wedge(_ep, value, 0); 741851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern} 742851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern 743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep) 744851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{ 745851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern if (!_ep || _ep->name == ep0name) 746851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return -EINVAL; 747851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return dummy_set_halt_and_wedge(_ep, 1, 1); 748851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern} 749851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = { 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable = dummy_enable, 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disable = dummy_disable, 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .alloc_request = dummy_alloc_request, 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .free_request = dummy_free_request, 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queue = dummy_queue, 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = dummy_dequeue, 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_halt = dummy_set_halt, 761851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern .set_wedge = dummy_set_wedge, 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */ 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget) 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timeval tv; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_gettimeofday (&tv); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tv.tv_usec / 1000; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget) 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 777cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 779cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = gadget_to_dummy_hcd(_gadget); 780cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE) 7815742b0c95026c817d9c266174ca39a909e8d38caAlan Stern | (1 << USB_DEVICE_REMOTE_WAKEUP)))) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 783cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0) 784391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ENOLINK; 785cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && 786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 787391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -EIO; 788391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 789391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* FIXME: What if the root hub is suspended but the port isn't? */ 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* hub notices our request, issues downstream resume, etc */ 792cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 1; 793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); 794cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 802cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum = (gadget_to_dummy_hcd(_gadget))->dum; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value) 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 810f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value) 811f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 812d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior struct dummy_hcd *dum_hcd; 813f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy *dum; 814f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned long flags; 815f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 816d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(_gadget); 817d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior dum = dum_hcd->dum; 818d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior 819f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock_irqsave (&dum->lock, flags); 820f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = (value != 0); 821d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior set_link_state(dum_hcd); 822f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock_irqrestore (&dum->lock, flags); 823d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 824f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern return 0; 825f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 826f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 8270f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget_driver *driver, 8280f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior int (*bind)(struct usb_gadget *)); 8290f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget_driver *driver); 8300f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = { 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame = dummy_g_get_frame, 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wakeup = dummy_wakeup, 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_selfpowered = dummy_set_selfpowered, 835f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern .pullup = dummy_pullup, 8360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .start = dummy_udc_start, 8370f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .stop = dummy_udc_stop, 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */ 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 84410523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf) 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = gadget_dev_to_dummy (dev); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !dum->driver->function) 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 852cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration. 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work. So most implementations of these api calls will rely on the 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware. But curious 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption. 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers: just add to a big root hub. 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8700f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget_driver *driver, 871b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König int (*bind)(struct usb_gadget *)) 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 873cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = &the_controller; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, i; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 880b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE side init ... the layer above hardware, which 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't enumerate without help from the driver we're binding. 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus = 0; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (mod_data.is_super_speed) 8911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->gadget.speed = driver->speed; 8927eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman else if (mod_data.is_high_speed) 8937eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, driver->speed); 8941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 8957eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman dum->gadget.speed = USB_SPEED_FULL; 8961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed < driver->speed) 8977eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman dev_dbg(udc_dev(dum), "This device can perform faster" 8987eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman " if you connect it to a %s port...\n", 8997eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman (driver->speed == USB_SPEED_SUPER ? 9007eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman "SuperSpeed" : "HighSpeed")); 9011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 9021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed == USB_SPEED_SUPER) { 9031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman for (i = 0; i < DUMMY_ENDPOINTS; i++) 9041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->ep[i].ep.max_streams = 0x10; 9051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->ep[0].ep.maxpacket = 9; 9060fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior } else { 9070fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior for (i = 0; i < DUMMY_ENDPOINTS; i++) 9080fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior dum->ep[i].ep.max_streams = 0; 9091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->ep[0].ep.maxpacket = 64; 9100fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior } 91199fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior 91299fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior if (dum->gadget.speed == USB_SPEED_SUPER) 91399fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior dum->gadget.is_otg = 91499fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); 91599fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior else 91699fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior dum->gadget.is_otg = 91799fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); 91899fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior 9195933101718ea3d283983a923c5524c88138e5564Alan Stern driver->driver.bus = NULL; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = driver; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.driver = &driver->driver; 922d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 924b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König retval = bind(&dum->gadget); 9255933101718ea3d283983a923c5524c88138e5564Alan Stern if (retval) { 9265933101718ea3d283983a923c5524c88138e5564Alan Stern dum->driver = NULL; 9275933101718ea3d283983a923c5524c88138e5564Alan Stern dum->gadget.dev.driver = NULL; 9285933101718ea3d283983a923c5524c88138e5564Alan Stern return retval; 9295933101718ea3d283983a923c5524c88138e5564Alan Stern } 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9312542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior /* khubd will enumerate this in a while */ 9322542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior dummy_pullup(&dum->gadget, 1); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget_driver *driver) 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 938cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = &the_controller; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9426bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell if (!driver || driver != dum->driver || !driver->unbind) 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 945d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9482542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior dummy_pullup(&dum->gadget, 0); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->unbind (&dum->gadget); 9515933101718ea3d283983a923c5524c88138e5564Alan Stern dum->gadget.dev.driver = NULL; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = NULL; 9532542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior 9542542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior dummy_pullup(&dum->gadget, 0); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 960d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be 961d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */ 962d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void 963d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev) 964d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 965cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return; 966d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9680fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum) 9690fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{ 9700fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior int i; 9710fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9720fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&dum->gadget.ep_list); 9730fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior for (i = 0; i < DUMMY_ENDPOINTS; i++) { 9740fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior struct dummy_ep *ep = &dum->ep[i]; 9750fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9760fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior if (!ep_name[i]) 9770fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior break; 9780fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.name = ep_name[i]; 9790fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.ops = &dummy_ep_ops; 9800fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); 9810fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->halted = ep->wedged = ep->already_seen = 9820fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->setup_stage = 0; 9830fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.maxpacket = ~0; 9840fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->last_io = jiffies; 9850fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->gadget = &dum->gadget; 9860fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->desc = NULL; 9870fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&ep->queue); 9880fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior } 9890fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9900fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior dum->gadget.ep0 = &dum->ep[0].ep; 9910fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior list_del_init(&dum->ep[0].ep.ep_list); 9920fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&dum->fifo_req.queue); 9930fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior} 9940fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9958364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev) 996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 997cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = &the_controller; 998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern int rc; 999d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.name = gadget_name; 1001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.ops = &dummy_ops; 1002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.is_dualspeed = 1; 1003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10040031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers dev_set_name(&dum->gadget.dev, "gadget"); 10058364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dum->gadget.dev.parent = &pdev->dev; 1006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.dev.release = dummy_gadget_release; 1007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern rc = device_register (&dum->gadget.dev); 100875d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar if (rc < 0) { 100975d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar put_device(&dum->gadget.dev); 1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 101175d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar } 1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10130fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior init_dummy_udc_hw(dum); 10140fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 10150f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); 10160f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior if (rc < 0) 10170f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior goto err_udc; 10180f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 1019efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern rc = device_create_file (&dum->gadget.dev, &dev_attr_function); 1020efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if (rc < 0) 10210f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior goto err_dev; 10220f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior platform_set_drvdata(pdev, dum); 10230f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior return rc; 10240f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 10250f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev: 10260f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&dum->gadget); 10270f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc: 10280f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior device_unregister(&dum->gadget.dev); 1029d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 1030d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 1031d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10328364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev) 1033d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 10348364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern struct dummy *dum = platform_get_drvdata (pdev); 1035d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&dum->gadget); 10378364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern platform_set_drvdata (pdev, NULL); 1038d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern device_remove_file (&dum->gadget.dev, &dev_attr_function); 1039d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern device_unregister (&dum->gadget.dev); 1040d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 1041d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 1042d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1043fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd, 1044fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior int suspend) 1045391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1046fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior spin_lock_irq(&dum->lock); 1047fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dum->udc_suspended = suspend; 1048d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior set_link_state(dum_hcd); 1049fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior spin_unlock_irq(&dum->lock); 1050fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior} 1051fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior 1052fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state) 1053fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{ 1054fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy *dum = platform_get_drvdata(pdev); 1055fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 1056391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1057fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 1058fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dummy_udc_pm(dum, dum_hcd, 1); 1059d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 1060391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1061391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1062391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1063fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev) 1064391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1065fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy *dum = platform_get_drvdata(pdev); 1066fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 1067391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1068fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 1069fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dummy_udc_pm(dum, dum_hcd, 0); 1070d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 1071391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1072391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1073391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 10743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = { 1075d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_udc_probe, 1076d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_udc_remove, 1077391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_udc_suspend, 1078391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_udc_resume, 10793ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 10803ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) gadget_name, 10813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 10823ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 1083d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 1084d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers. 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller. 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback. that callback connects writes from 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules. 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue ( 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb, 110255016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 1104cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1107e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb->transfer_buffer && urb->transfer_buffer_length) 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp = kmalloc (sizeof *urbp, mem_flags); 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urbp) 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp->urb = urb; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1117cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1118cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1119e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_link_urb_to_ep(hcd, urb); 1120e9df41c5c5899259541dc928872cad4d07b82076Alan Stern if (rc) { 1121e9df41c5c5899259541dc928872cad4d07b82076Alan Stern kfree(urbp); 1122e9df41c5c5899259541dc928872cad4d07b82076Alan Stern goto done; 1123e9df41c5c5899259541dc928872cad4d07b82076Alan Stern } 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1125cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum_hcd->udev) { 1126cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->udev = urb->dev; 1127cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_get_dev(dum_hcd->udev); 1128cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (unlikely(dum_hcd->udev != urb->dev)) 1129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n"); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->hcpriv = urbp; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipetype (urb->pipe) == PIPE_CONTROL) 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 1; /* mark as a new urb */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kick the scheduler, it'll do the rest */ 1137cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!timer_pending(&dum_hcd->timer)) 1138cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies + 1); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1140e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done: 1141cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 1142e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1145e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1147cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 1148391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned long flags; 1149e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 1150391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1151391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* giveback happens automatically in timer callback, 1152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern * so make sure the callback happens */ 1153cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1154cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1155e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1156e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_check_unlink_urb(hcd, urb, status); 1157cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && 1158cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman !list_empty(&dum_hcd->urbp_list)) 1159cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies); 1160e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 1162e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */ 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 11674d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, 11684d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern int *status) 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop: 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if there's no request queued, the device is NAKing; return */ 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned host_len, dev_len, len; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int is_short, to_host; 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rescan = 0; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1..N packets of ep->ep.maxpacket each ... the last one 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be short (including zero length). 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * writer can send a zlp explicitly (length 0) or implicitly 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (length mod maxpacket zero, and 'zero' flag); they always 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * terminate reads. 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_len = urb->transfer_buffer_length - urb->actual_length; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_len = req->req.length - req->req.actual; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (host_len, dev_len); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME update emulated data toggle too */ 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_host = usb_pipein (urb->pipe); 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely (len == 0)) 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = 1; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ubuf, *rbuf; 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not enough bandwidth left? */ 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (limit < ep->ep.maxpacket && limit < len) 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (len, (unsigned) limit); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use an extra pass for the final short packet */ 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > ep->ep.maxpacket) { 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= (len % ep->ep.maxpacket); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = (len % ep->ep.maxpacket) != 0; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* else transfer packet(s) */ 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ubuf = urb->transfer_buffer + urb->actual_length; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rbuf = req->req.buf + req->req.actual; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (to_host) 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (ubuf, rbuf, len); 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (rbuf, ubuf, len); 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit -= len; 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length += len; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.actual += len; 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* short packets terminate, maybe with overflow/underflow. 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's only really an error to write too much. 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partially filling a buffer optionally blocks queue advances 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (so completion handlers can clean up the queue) but we don't 1231b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern * need to emulate such data-in-flight. 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_short) { 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len == dev_len) { 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 12364d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (to_host) { 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev_len > host_len) 12404d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = -EOVERFLOW; 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12424d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!to_host) { 12444d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len > dev_len) 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* many requests terminate without a short packet */ 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.length == req->req.actual 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !req->req.zero) 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length == urb->actual_length 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !(urb->transfer_flags 12584d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern & URB_ZERO_PACKET)) 12594d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device side completion --> continuable */ 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.status != -EINPROGRESS) { 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* requests might have been unlinked... */ 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* host side completion --> terminate */ 12754d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (*status != -EINPROGRESS) 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* rescan to continue with any other queued i/o */ 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rescan) 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto top; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit = ep->ep.maxpacket; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->gadget.speed == USB_SPEED_HIGH) { 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* high bandwidth mode */ 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = le16_to_cpu(ep->desc->wMaxPacketSize); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (tmp >> 11) & 0x03; 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp *= 8 /* applies to entire frame */; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit += limit * tmp; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed == USB_SPEED_SUPER) { 12991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman switch (ep->desc->bmAttributes & 0x03) { 13001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_ISOC: 13011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Sec. 4.4.8.2 USB3.0 Spec */ 13021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman limit = 3 * 16 * 1024 * 8; 13031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 13041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_INT: 13051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Sec. 4.4.7.2 USB3.0 Spec */ 13061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman limit = 3 * 1024 * 8; 13071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 13081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_BULK: 13091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman default: 13101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 13111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 13121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1316cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd) ((dum_hcd->port_status & \ 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_SUSPEND)) \ 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? 13261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->ss_hcd : dum->hs_hcd))) 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((address & ~USB_DIR_IN) == 0) 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &dum->ep [0]; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < DUMMY_ENDPOINTS; i++) { 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = &dum->ep [i]; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep->desc) 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc->bEndpointAddress == address) 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ep; 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest (Dev_Request | USB_DIR_IN) 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest (Intf_Request | USB_DIR_IN) 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest (Ep_Request | USB_DIR_IN) 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 13518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/** 13528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers 13538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller) 13548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle 13558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control 13568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * request 13578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status 13588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * 13598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled 13608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * 1 - if the request wasn't handles 13618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * error code on error 13628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */ 1363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, 13648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman struct usb_ctrlrequest *setup, 13658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman int *status) 13668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{ 13678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman struct dummy_ep *ep2; 1368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 13698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman int ret_val = 1; 13708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman unsigned w_index; 13718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman unsigned w_value; 13728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 13738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_index = le16_to_cpu(setup->wIndex); 13748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value = le16_to_cpu(setup->wValue); 13758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (setup->bRequest) { 13768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_SET_ADDRESS: 13778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType != Dev_Request) 13788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 13798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->address = w_value; 13808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 13818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dev_dbg(udc_dev(dum), "set_address = %d\n", 13828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value); 13838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 13848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 13858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_SET_FEATURE: 13868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_Request) { 13878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 13888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (w_value) { 13898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_REMOTE_WAKEUP: 13908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 13918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_B_HNP_ENABLE: 13928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.b_hnp_enable = 1; 13938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 13948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_A_HNP_SUPPORT: 13958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.a_hnp_support = 1; 13968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 13978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_A_ALT_HNP_SUPPORT: 13988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.a_alt_hnp_support = 1; 13998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U1_ENABLE: 14011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U1_ENABLED; 14041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U2_ENABLE: 14081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U2_ENABLED; 14111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_LTM_ENABLE: 14151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_LTM_ENABLED; 14181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman default: 14228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 14238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (ret_val == 0) { 14258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->devstatus |= (1 << w_value); 14268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 14278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == Ep_Request) { 14298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* endpoint halt */ 14308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 14318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2 || ep2->ep.name == ep0name) { 14328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 14338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2->halted = 1; 14368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 14378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 14388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_CLEAR_FEATURE: 14418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_Request) { 14428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 14438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (w_value) { 14448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_REMOTE_WAKEUP: 14458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value = USB_DEVICE_REMOTE_WAKEUP; 14468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U1_ENABLE: 14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U1_ENABLED; 14511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U2_ENABLE: 14551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U2_ENABLED; 14581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_LTM_ENABLE: 14621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 14631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 14641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_LTM_ENABLED; 14651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 14661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 14671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman default: 14698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 14708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (ret_val == 0) { 14738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->devstatus &= ~(1 << w_value); 14748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 14758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == Ep_Request) { 14778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* endpoint halt */ 14788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 14798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2) { 14808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 14818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2->wedged) 14848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2->halted = 0; 14858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_GET_STATUS: 14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_InRequest 14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman || setup->bRequestType == Intf_InRequest 14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman || setup->bRequestType == Ep_InRequest) { 14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman char *buf; 14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* 14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * device: remote wakeup, selfpowered 14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * interface: nothing 14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * endpoint: halt 14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */ 14998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf = (char *)urb->transfer_buffer; 15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (urb->transfer_buffer_length > 0) { 15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Ep_InRequest) { 15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2) { 15048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = ep2->halted; 15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == 15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman Dev_InRequest) { 15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = (u8)dum->devstatus; 15118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else 15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = 0; 15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (urb->transfer_buffer_length > 1) 15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[1] = 0; 15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman urb->actual_length = min_t(u32, 2, 15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman urb->transfer_buffer_length); 15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman return ret_val; 15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman} 15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq(). 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1529cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd) 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1531cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd; 1532cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp, *tmp; 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit, total; 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* simplistic model for one frame's bandwidth */ 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 8/*bytes*/ * 12/*packets*/; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 64/*bytes*/ * 19/*packets*/; 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 15501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Bus speed is 500000 bytes/ms, so use a little less */ 15511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman total = 490000; 15521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1554cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME if HZ != 1000 this will probably misbehave ... */ 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look at each urb queued by the host side driver */ 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1563cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum_hcd->udev) { 1564cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "timer fired with no URBs pending?\n"); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep_name [i]) 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->ep [i].already_seen = 0; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart: 1577cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) { 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 address; 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = NULL; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 15834d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern int status = -EINPROGRESS; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = urbp->urb; 1586eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern if (urb->unlinked) 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 1588cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) 1589391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern continue; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = usb_pipetype (urb->pipe); 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* used up this frame's non-periodic bandwidth? 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME there's infinite bandwidth for control and 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * periodic transfers ... unrealistic. 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total <= 0 && type == PIPE_BULK) 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the gadget's ep for this request (if configured) */ 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address = usb_pipeendpoint (urb->pipe); 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipein (urb->pipe)) 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address |= USB_DIR_IN; 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = find_endpoint(dum, address); 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) { 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set_configuration() disagreement */ 1606cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no ep configured for urb %p\n", 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb); 16094d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPROTO; 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->already_seen) 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 1; 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && urb->error_count) { 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 1; /* a new urb */ 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 0; 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->halted && !ep->setup_stage) { 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE: must not be iso! */ 1622cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n", 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name, urb); 16244d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME make sure both ends agree on maxpacket */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* handle control requests */ 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && ep->setup_stage) { 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ctrlrequest setup; 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = 1; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = *(struct usb_ctrlrequest*) urb->setup_packet; 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* paranoia, in case of stale queued data */ 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 1639d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "stale req = %p\n", 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req); 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 0; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver never sees set_address or operations 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on standard feature flags. some hardware doesn't 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even expose them. 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 0; 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1657cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman value = handle_control_request(dum_hcd, urb, &setup, 16588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman &status); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver handles all other requests. block 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until setup() returns; no reentrancy issues etc. 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 0) { 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = dum->driver->setup (&dum->gadget, 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &setup); 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= 0) { 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no delays (max 64KB data stage) */ 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 64*1024; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto treat_control_like_bulk; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error, see below */ 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value < 0) { 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value != -EOPNOTSUPP) 1679d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "setup --> %d\n", 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value); 16824d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = 0; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non-control requests */ 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = total; 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_ISOCHRONOUS: 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use urb->iso_frame_desc[i]. 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete whether or not ep has requests queued. 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * report random errors, to debug drivers. 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 16994d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -ENOSYS; 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this almost certainly polls too fast. 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // case PIPE_BULK: case PIPE_CONTROL: 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds treat_control_like_bulk: 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 17134d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern total = transfer(dum, urb, ep, limit, &status); 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* incomplete transfer? */ 17184d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (status == -EINPROGRESS) 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb: 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&urbp->urbp_list); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (urbp); 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep) 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = ep->setup_stage = 0; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1727cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 1729cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status); 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1735cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (list_empty(&dum_hcd->urbp_list)) { 1736cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_dev(dum_hcd->udev); 1737cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->udev = NULL; 1738cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { 1739391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* want a 1 msec delay here */ 1740cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1)); 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \ 1749c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern ((USB_PORT_STAT_C_CONNECTION \ 1750c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_ENABLE \ 1751c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_SUSPEND \ 1752c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_OVERCURRENT \ 1753c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_RESET) << 16) 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf) 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1757cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1759391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern int retval = 0; 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1763cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1764541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) 1765391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern goto done; 1766f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1767cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) { 1768cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1769cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 1770cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 1771f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 1772f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1773cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & PORT_C_MASK) != 0) { 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = (1 << 1); 1775cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n", 1776cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status); 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 1; 1778cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED) 1779391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_resume_root_hub (hcd); 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone: 1782cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 17871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc) 17881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 17891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman memset(desc, 0, sizeof *desc); 17901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bDescriptorType = 0x2a; 17911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bDescLength = 12; 17921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->wHubCharacteristics = cpu_to_le16(0x0001); 17931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bNbrPorts = 1; 17941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ 17951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->u.ss.DeviceRemovable = 0xffff; 17961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 17971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 17981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc) 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (desc, 0, sizeof *desc); 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescriptorType = 0x29; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescLength = 9; 1804fd05e720099e8eeddb378305d1a41c1445344b91Al Viro desc->wHubCharacteristics = cpu_to_le16(0x0001); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bNbrPorts = 1; 1806dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[0] = 0xff; 1807dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[1] = 0xff; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control ( 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 typeReq, 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wValue, 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wIndex, 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wLength 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 1818cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1822541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) 1823391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ETIMEDOUT; 1824391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1825cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1826cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 1827cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (typeReq) { 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearHubFeature: 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearPortFeature: 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 18341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 18351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 18361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_SUSPEND req not " 18371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 3.0 roothub\n"); 18381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 18391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 1840cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) { 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20msec resume signaling */ 1842cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 1; 1843cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + 1844f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern msecs_to_jiffies(20); 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 18481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 18491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum_hcd->port_status & USB_PORT_STAT_POWER) 18501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 18511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "power-off\n"); 18521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 18531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum_hcd->port_status & 18541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_STAT_POWER) 18551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 18561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "power-off\n"); 1857f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1859cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~(1 << wValue); 1860cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubDescriptor: 18641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3 && 18651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (wLength < USB_DT_SS_HUB_SIZE || 18661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman wValue != (USB_DT_SS_HUB << 8))) { 18671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 18681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "Wrong hub descriptor type for " 18691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB 3.0 roothub.\n"); 18701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 18711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 18721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) 18731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ss_hub_descriptor((struct usb_hub_descriptor *) buf); 18741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 18751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hub_descriptor((struct usb_hub_descriptor *) buf); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubStatus: 1878551509d267905705f6d723e51ec706916f06b859Harvey Harrison *(__le32 *) buf = cpu_to_le32 (0); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetPortStatus: 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wIndex != 1) 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resets or resumes must GetPortStatus to 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete it!! 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1887cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->resuming && 1888cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman time_after_eq(jiffies, dum_hcd->re_timeout)) { 1889cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1890cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1892cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 && 1893cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman time_after_eq(jiffies, dum_hcd->re_timeout)) { 1894cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16); 1895cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_RESET; 1896cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->dum->pullup) { 1897cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_ENABLE; 18981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 18991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed < HCD_USB3) { 19001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman switch (dum_hcd->dum->gadget.speed) { 19011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_HIGH: 19021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 19031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_HIGH_SPEED; 19041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 19051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_LOW: 19061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->dum->gadget.ep0-> 19071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman maxpacket = 8; 19081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 19091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_LOW_SPEED; 19101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 19111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman default: 19121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->dum->gadget.speed = 19131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SPEED_FULL; 19141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 19151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1919cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 1920cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status); 1921cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetHubFeature: 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetPortFeature: 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_LINK_STATE: 19291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_LINK_STATE req not " 19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 19331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 19341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 19351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 19361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * Since this is dummy we don't have an actual link so 19371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * there is nothing to do for the SET_LINK_STATE cmd 19381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 19391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 19401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_U1_TIMEOUT: 19411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_U2_TIMEOUT: 19421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* TODO: add suspend/resume support! */ 19431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 19441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_U1/2_TIMEOUT req not " 19461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 19471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 19481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 19491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 19511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Applicable only for USB2.0 hub */ 19521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 19531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_SUSPEND req not " 19551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 3.0 roothub\n"); 19561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 19571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 1958cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->active) { 1959cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_SUSPEND; 1960f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1961f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* HNP would happen here; for now we 1962f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern * assume b_bus_req is always true. 1963f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern */ 1964cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 1965f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (((1 << USB_DEVICE_B_HNP_ENABLE) 1966cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman & dum_hcd->dum->devstatus) != 0) 1967cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19685742b0c95026c817d9c266174ca39a909e8d38caAlan Stern "no HNP yet!\n"); 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1971f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern case USB_PORT_FEAT_POWER: 19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) 19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_SS_PORT_STAT_POWER; 19741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 19751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_POWER; 1976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 1977f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern break; 19781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_BH_PORT_RESET: 19791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Applicable only for USB3.0 hub */ 19801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 19811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_BH_PORT_RESET req not " 19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 19841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* FALLS THROUGH */ 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_RESET: 1988f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* if it's already enabled, disable */ 19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 19911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 19921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_SS_PORT_STAT_POWER | 19931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION | 19941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_RESET); 19951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 19961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE 1997f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_LOW_SPEED 1998f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_HIGH_SPEED); 1999cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman /* 2000cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * We want to reset device status. All but the 2001cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * Self powered feature 2002cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman */ 2003cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->dum->devstatus &= 2004cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman (1 << USB_DEVICE_SELF_POWERED); 20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * FIXME USB3.0: what is the correct reset signaling 20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * interval? Is it still 50msec as for HS? 20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2009cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); 2010f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 20131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 20141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_STAT_POWER) != 0) { 20151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (1 << wValue); 20161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state(dum_hcd); 20171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 20191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 20201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_POWER) != 0) { 20211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (1 << wValue); 20221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state(dum_hcd); 20231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case GetPortErrorCount: 20271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 20281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "GetPortErrorCount req not " 20301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 20311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* We'll always return 0 since this is a dummy hub */ 20341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *(__le32 *) buf = cpu_to_le32(0); 20351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case SetHubDepth: 20371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 20381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "SetHubDepth req not supported for " 20401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB 2.0 roothub\n"); 20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2045cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "hub control req%04x v%04x i%04x l%d\n", 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds typeReq, wValue, wIndex, wLength); 20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror: 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* "protocol stall" on error */ 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2052cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2053685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern 2054cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & PORT_C_MASK) != 0) 2055685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern usb_hcd_poll_rh_status (hcd); 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20590c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd) 2060391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2061cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2062391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 2063441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); 20643cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 2065cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irq(&dum_hcd->dum->lock); 2066cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_SUSPENDED; 2067cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 20683cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_SUSPENDED; 2069cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irq(&dum_hcd->dum->lock); 2070391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 2071391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2072391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 20730c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd) 2074391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2075cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 20763cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 20773cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 2078441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); 2079391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 2080cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irq(&dum_hcd->dum->lock); 2081541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) { 2082cfa59dab27d1b282886e7772a8f9548236883892Alan Stern rc = -ESHUTDOWN; 20833cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else { 2084cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 2085cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 2086cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!list_empty(&dum_hcd->urbp_list)) 2087cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies); 20883cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_RUNNING; 20893cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } 2090cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irq(&dum_hcd->dum->lock); 20913cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 2092391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb) 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ep = usb_pipeendpoint (urb->pipe); 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return snprintf (buf, size, 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "urb/%p %s ep%d%s%s len %d/%d\n", 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb, 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->dev->speed) { 21067c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_SPEED_LOW: 21077c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "ls"; 21087c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 21097c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_SPEED_FULL: 21107c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "fs"; 21117c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 21127c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_SPEED_HIGH: 21137c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "hs"; 21147c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 21151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 21161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman s = "ss"; 21171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 21187c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman default: 21197c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "?"; 21207c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s; }), 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; \ 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { \ 21257c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case PIPE_CONTROL: \ 21267c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = ""; \ 21277c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 21287c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case PIPE_BULK: \ 21297c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-bulk"; \ 21307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 21317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case PIPE_INTERRUPT: \ 21327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-int"; \ 21337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 21347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman default: \ 21357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-iso"; \ 21367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s;}), 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length, urb->transfer_buffer_length); 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 214210523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf) 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd = dev_get_drvdata (dev); 2145cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = 0; 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2150cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2151cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) { 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t temp; 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += temp; 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size += temp; 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2158cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd) 21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 21661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman init_timer(&dum_hcd->timer); 21671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->timer.function = dummy_timer; 21681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->timer.data = (unsigned long)dum_hcd; 21691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 21701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman INIT_LIST_HEAD(&dum_hcd->urbp_list); 21711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; 21721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; 21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; 21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG 21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1; 21761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif 21771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 21781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 21791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 21801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); 21811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 21821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2183cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd) 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2185cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER side init ... we emulate a root hub that'll only ever 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * talk to one device (the slave side). Also appears in sysfs, 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just like more familiar pci-based HCDs. 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!usb_hcd_is_primary_hcd(hcd)) 21931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dummy_start_ss(dum_hcd); 21941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_init(&dum_hcd->dum->lock); 2196cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman init_timer(&dum_hcd->timer); 2197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->timer.function = dummy_timer; 2198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->timer.data = (unsigned long)dum_hcd; 2199cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman INIT_LIST_HEAD(&dum_hcd->urbp_list); 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2203caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern hcd->power_budget = POWER_BUDGET; 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd->state = HC_STATE_RUNNING; 2205685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern hcd->uses_new_polling = 1; 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22075742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG 22085742b0c95026c817d9c266174ca39a909e8d38caAlan Stern hcd->self.otg_port = 1; 22095742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif 22105742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 2212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd) 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum = (hcd_to_dummy_hcd(hcd))->dum; 2220cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); 2221cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_gadget_unregister_driver(dum->driver); 2222cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd) 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dummy_g_get_frame (NULL); 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd) 2233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{ 2234cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (usb_hcd_is_primary_hcd(hcd)) { 2235cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); 2236cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd->dum = &the_controller; 22371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 22381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * Mark the first roothub as being USB 2.0. 22391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * The USB 3.0 roothub will be registered later by 22401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * dummy_hcd_probe() 22411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2242cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hcd->speed = HCD_USB2; 2243cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hcd->self.root_hub->speed = USB_SPEED_HIGH; 22441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 22451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); 22461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd->dum = &the_controller; 22471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hcd->speed = HCD_USB3; 22481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hcd->self.root_hub->speed = USB_SPEED_SUPER; 2249cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } 2250cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return 0; 2251cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman} 2252cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 22531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */ 22541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, 22551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_host_endpoint **eps, unsigned int num_eps, 22561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman unsigned int num_streams, gfp_t mem_flags) 22571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 22581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) 22591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), 22601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "%s() - ERROR! Not supported for USB2.0 roothub\n", 22611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman __func__); 22621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 22631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 22641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 22651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */ 22661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev, 22671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_host_endpoint **eps, unsigned int num_eps, 22681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman gfp_t mem_flags) 22691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 22701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) 22711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), 22721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "%s() - ERROR! Not supported for USB2.0 roothub\n", 22731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman __func__); 22741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 22751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 22761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 22771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = { 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = (char *) driver_name, 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .product_desc = "Dummy host controller", 2280cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman .hcd_priv_size = sizeof(struct dummy_hcd), 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .flags = HCD_USB3 | HCD_SHARED, 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman .reset = dummy_setup, 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = dummy_start, 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = dummy_stop, 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_enqueue = dummy_urb_enqueue, 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_dequeue = dummy_urb_dequeue, 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame_number = dummy_h_get_frame, 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_status_data = dummy_hub_status, 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_control = dummy_hub_control, 22950c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_suspend = dummy_bus_suspend, 22960c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_resume = dummy_bus_resume, 22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .alloc_streams = dummy_alloc_streams, 22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .free_streams = dummy_free_streams, 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23028364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev) 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2304cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct usb_hcd *hs_hcd; 23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_hcd *ss_hcd; 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!mod_data.is_super_speed) 23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd.flags = HCD_USB2; 2312cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); 2313cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!hs_hcd) 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2315cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hs_hcd->has_tt = 1; 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2317cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman retval = usb_add_hcd(hs_hcd, 0, 0); 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 0) { 2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_hcd(hs_hcd); 23201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return retval; 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 23231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (mod_data.is_super_speed) { 23241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, 23251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_name(&pdev->dev), hs_hcd); 23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!ss_hcd) { 23271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman retval = -ENOMEM; 23281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto dealloc_usb2_hcd; 23291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 23301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 23311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman retval = usb_add_hcd(ss_hcd, 0, 0); 23321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (retval) 23331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto put_usb3_hcd; 23341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 23351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 23361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 23371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd: 23381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(ss_hcd); 23391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd: 23401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(hs_hcd); 23411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.hs_hcd = the_controller.ss_hcd = NULL; 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2345cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev) 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2347cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum; 2348cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 2349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum; 23501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 23511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->ss_hcd) { 23521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); 23531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); 23541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 23551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 2357cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 23581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2359cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd = NULL; 23601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd = NULL; 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2362d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23658364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state) 2366391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2367391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 2368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 23693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 2370391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 2371441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dev_dbg (&pdev->dev, "%s\n", __func__); 2372391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 23733cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd = platform_get_drvdata (pdev); 2374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 2375cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { 23763cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); 23773cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern rc = -EBUSY; 23783cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else 23793cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 23803cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 2381391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2382391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 23838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev) 2384391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2385391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 2386391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 2387441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dev_dbg (&pdev->dev, "%s\n", __func__); 2388391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 23893cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd = platform_get_drvdata (pdev); 23903cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 2391391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_poll_rh_status (hcd); 2392391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 2393391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2394391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 23953ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = { 2396d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_hcd_probe, 2397d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_hcd_remove, 2398391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_hcd_suspend, 2399391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_hcd_resume, 24003ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 24013ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) driver_name, 24023ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 24033ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 2404d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2406d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2408a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev; 2409a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev; 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void) 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2413a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern int retval = -ENOMEM; 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_disabled ()) 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2417d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 24187eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman if (!mod_data.is_high_speed && mod_data.is_super_speed) 24197eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman return -EINVAL; 24207eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman 2421a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern the_hcd_pdev = platform_device_alloc(driver_name, -1); 2422a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (!the_hcd_pdev) 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2424a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern the_udc_pdev = platform_device_alloc(gadget_name, -1); 2425a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (!the_udc_pdev) 2426a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_alloc_udc; 2427d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2428a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_driver_register(&dummy_hcd_driver); 2429a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (retval < 0) 2430a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_register_hcd_driver; 2431a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_driver_register(&dummy_udc_driver); 2432d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2433d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern goto err_register_udc_driver; 2434d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2435a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_device_add(the_hcd_pdev); 2436d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2437a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_add_hcd; 24381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!the_controller.hs_hcd || 24391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (!the_controller.ss_hcd && mod_data.is_super_speed)) { 2440865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior /* 2441865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * The hcd was added successfully but its probe function failed 2442865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * for some reason. 2443865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior */ 2444865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior retval = -EINVAL; 2445865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior goto err_add_udc; 2446865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior } 2447a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_device_add(the_udc_pdev); 2448d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2449a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_add_udc; 2450865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior if (!platform_get_drvdata(the_udc_pdev)) { 2451865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior /* 2452865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * The udc was added successfully but its probe function failed 2453865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * for some reason. 2454865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior */ 2455865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior retval = -EINVAL; 2456865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior goto err_probe_udc; 2457865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior } 2458d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return retval; 2459d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2460865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc: 2461865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior platform_device_del(the_udc_pdev); 2462a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc: 2463a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_del(the_hcd_pdev); 2464a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd: 2465a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_udc_driver); 2466d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver: 2467a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_hcd_driver); 2468a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver: 2469a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_put(the_udc_pdev); 2470a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc: 2471a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_put(the_hcd_pdev); 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init); 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void) 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2478a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_unregister(the_udc_pdev); 2479a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_unregister(the_hcd_pdev); 2480a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_udc_driver); 2481a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_hcd_driver); 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup); 2484