dummy_hcd.c revision 4d2f110c51eec853c50f68cf068888a77551c8d3
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> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_gadget.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../core/hcd.h" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Host+Gadget Emulator" 62391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION "02 May 2005" 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep { 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_io; /* jiffies timestamp */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *desc; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep ep; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned halted : 1; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned already_seen : 1; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned setup_stage : 1; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request { 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; /* ep's requests */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request req; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_ep, struct dummy_ep, ep); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_request *_req) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_req, struct dummy_request, req); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types: 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * number can be changed. Names like "ep-a" are used for this type. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Fixed Function: in other cases. some characteristics may be mutable; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that'd be hardware-specific. Names like "ep12out-bulk" are used. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0"; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = { 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0name, /* everyone has ep0 */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* act like a net2280: high speed, six configurable endpoints */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like pxa250: fifteen fixed function endpoints */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep15in-int", 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like sa1100: two fixed function endpoints */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1out-bulk", "ep2in-bulk", 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 13652950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 139d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE 64 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp { 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 148391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state { 149391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RESET, 150391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_SUSPENDED, 151391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RUNNING 152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}; 153391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy { 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE/GADGET side support 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep ep [DUMMY_ENDPOINTS]; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget gadget; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget_driver *driver; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request fifo_req; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fifo_buf [FIFO_SIZE]; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 devstatus; 167391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned udc_suspended:1; 168f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned pullup:1; 169f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned active:1; 170f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned old_active:1; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER/HOST side support 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 175391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern enum dummy_rh_state rh_state; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timer_list timer; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 port_status; 178f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern u32 old_status; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned resuming:1; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long re_timeout; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *udev; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (struct dummy *) (hcd->hcd_priv); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct usb_hcd *dummy_to_hcd (struct dummy *dum) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of((void *) dum, struct usb_hcd, hcd_priv); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct device *dummy_dev (struct dummy *dum) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dummy_to_hcd(dum)->self.controller; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum) 202d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 203d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return dum->gadget.dev.parent; 204d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 205d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (ep->gadget, struct dummy, gadget); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget) 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (gadget, struct dummy, gadget); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (dev, struct dummy, gadget.dev); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy *the_controller; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */ 226f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 227f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */ 228f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep) 229f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 230f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern while (!list_empty (&ep->queue)) { 231f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_request *req; 232f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 233f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req = list_entry (ep->queue.next, struct dummy_request, queue); 234f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern list_del_init (&req->queue); 235f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req->req.status = -ESHUTDOWN; 236f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 237f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock (&dum->lock); 238f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req->req.complete (&ep->ep, &req->req); 239f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock (&dum->lock); 240f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 241f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 242f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 243f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void 245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum) 246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_ep *ep; 248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* prevent any more requests */ 250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->address = 0; 251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* The timer is left running so that outstanding URBs can fail */ 253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* nuke any pending requests first, so driver i/o is quiesced */ 255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) 256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern nuke (dum, ep); 257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* driver now does any non-usb quiescing necessary */ 259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void 263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternset_link_state (struct dummy *dum) 264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->active = 0; 266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_POWER) == 0) 267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status = 0; 268391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 269391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* UDC suspend must cause a disconnect */ 270391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern else if (!dum->pullup || dum->udc_suspended) { 271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status &= ~(USB_PORT_STAT_CONNECTION | 272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern USB_PORT_STAT_ENABLE | 273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern USB_PORT_STAT_LOW_SPEED | 274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern USB_PORT_STAT_HIGH_SPEED | 275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern USB_PORT_STAT_SUSPEND); 276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) 277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); 278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } else { 279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= USB_PORT_STAT_CONNECTION; 280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) 281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); 282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) 283f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status &= ~USB_PORT_STAT_SUSPEND; 284391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && 285391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->rh_state != DUMMY_RH_SUSPENDED) 286f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->active = 1; 287f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 288f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 289f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) 290f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->resuming = 0; 291f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 292f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || 293f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern (dum->port_status & USB_PORT_STAT_RESET) != 0) { 294f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && 295f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern (dum->old_status & USB_PORT_STAT_RESET) == 0 && 296f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->driver) { 297f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern stop_activity (dum); 298f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock (&dum->lock); 299f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->driver->disconnect (&dum->gadget); 300f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock (&dum->lock); 301f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 302f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } else if (dum->active != dum->old_active) { 303f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->old_active && dum->driver->suspend) { 304f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock (&dum->lock); 305f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->driver->suspend (&dum->gadget); 306f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock (&dum->lock); 307f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } else if (!dum->old_active && dum->driver->resume) { 308f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock (&dum->lock); 309f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->driver->resume (&dum->gadget); 310f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock (&dum->lock); 311f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 312f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 313f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 314f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->old_status = dum->port_status; 315f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->old_active = dum->active; 316f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 317f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 318f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/ 319f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state. All the work is done when the host 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation. Real device controller 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc. 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dum->port_status & USB_PORT_STAT_ENABLE) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !desc || ep->desc || _ep->name == ep0name 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || desc->bDescriptorType != USB_DT_ENDPOINT) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !is_enabled (dum)) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* drivers must not request bad settings, since lower levels 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (hardware or its drivers) may not check. some endpoints 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't do iso, many have maxpacket limitations, etc. 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since this "hardware" driver is here to help debugging, we 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have some extra sanity checks. (there could be more though, 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * especially for "ep9out" style fixed function ones.) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso") 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) { 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max == 512) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* conserve return statements */ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (max) { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: case 16: case 32: case 64: 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we'll fake any legal size */ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 64) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 8) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-bulk") 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1023) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* few chips support control except on ep0 */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->maxpacket = max; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = desc; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 423d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->name, 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bEndpointAddress & 0x0f, 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *val; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: val = "intr"; break; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: val = "ctrl"; break; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; val; }), 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* at this point real hardware should be NAKing transfers 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to that endpoint, until a buffer is queued to it. 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !ep->desc || _ep->name == ep0name) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nuke (dum, ep); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 462d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request * 46755016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4767039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn req = kzalloc(sizeof(*req), mem_flags); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&req->queue); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &req->req; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON (!list_empty (&req->queue)); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (req); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5045db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req, 50555016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_req || !list_empty (&req->queue) || !_req->complete) 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || (!ep->desc && _ep->name != ep0name)) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !is_enabled (dum)) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 525d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, _req, _ep->name, _req->length, _req->buf); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -EINPROGRESS; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = 0; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* implement an emulated single-request FIFO */ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&dum->fifo_req.queue) && 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&ep->queue) && 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->length <= FIFO_SIZE) { 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = &dum->fifo_req; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req = *_req; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.buf = dum->fifo_buf; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (dum->fifo_buf, _req->buf, _req->length); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.context = dum; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete = fifo_complete; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = _req->length; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = 0; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&req->queue, &ep->queue); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware would likely enable transfers here, in case 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it'd been left NAKing. 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = -EINVAL; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req = NULL; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !_req) 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 576b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern local_irq_save (flags); 577b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern spin_lock (&dum->lock); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (&req->req == _req) { 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -ECONNRESET; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 586b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern spin_unlock (&dum->lock); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 589d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dequeued req %p from %s, len %d buf %p\n", 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req, _ep->name, _req->length, _req->buf); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 594b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern local_irq_restore (flags); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_set_halt (struct usb_ep *_ep, int value) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!value) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !list_empty (&ep->queue)) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 1; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME clear emulated data toggle too */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = { 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable = dummy_enable, 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disable = dummy_disable, 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .alloc_request = dummy_alloc_request, 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .free_request = dummy_free_request, 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queue = dummy_queue, 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = dummy_dequeue, 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_halt = dummy_set_halt, 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timeval tv; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_gettimeofday (&tv); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tv.tv_usec / 1000; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = gadget_to_dummy (_gadget); 650391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) 6515742b0c95026c817d9c266174ca39a909e8d38caAlan Stern | (1 << USB_DEVICE_REMOTE_WAKEUP)))) 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 653391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) 654391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ENOLINK; 655391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && 656391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->rh_state != DUMMY_RH_SUSPENDED) 657391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -EIO; 658391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 659391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* FIXME: What if the root hub is suspended but the port isn't? */ 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* hub notices our request, issues downstream resume, etc */ 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 1; 663f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->re_timeout = jiffies + msecs_to_jiffies(20); 664685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = gadget_to_dummy (_gadget); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value) 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 680f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value) 681f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 682f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy *dum; 683f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned long flags; 684f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 685f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum = gadget_to_dummy (_gadget); 686f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock_irqsave (&dum->lock, flags); 687f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = (value != 0); 688f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 689f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock_irqrestore (&dum->lock, flags); 690685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern 691685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern usb_hcd_poll_rh_status (dummy_to_hcd (dum)); 692f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern return 0; 693f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 694f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = { 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame = dummy_g_get_frame, 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wakeup = dummy_wakeup, 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_selfpowered = dummy_set_selfpowered, 699f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern .pullup = dummy_pullup, 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 70610523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf) 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = gadget_dev_to_dummy (dev); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !dum->driver->function) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 714cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration. 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work. So most implementations of these api calls will rely on the 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware. But curious 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption. 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers: just add to a big root hub. 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_register_driver (struct usb_gadget_driver *driver) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = the_controller; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, i; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver) 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 7426bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell if (!driver->bind || !driver->setup 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || driver->speed == USB_SPEED_UNKNOWN) 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE side init ... the layer above hardware, which 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't enumerate without help from the driver we're binding. 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7505742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus = 0; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&dum->gadget.ep_list); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = &dum->ep [i]; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep_name [i]) 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name = ep_name [i]; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.ops = &dummy_ep_ops; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = ep->already_seen = ep->setup_stage = 0; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.maxpacket = ~0; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->gadget = &dum->gadget; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&ep->queue); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0 = &dum->ep [0].ep; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->ep [0].ep.maxpacket = 64; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&dum->ep [0].ep.ep_list); 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&dum->fifo_req.queue); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = driver; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.driver = &driver->driver; 777d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 779efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if ((retval = driver->bind (&dum->gadget)) != 0) 780efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern goto err_bind_gadget; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.bus = dum->gadget.dev.parent->bus; 783efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if ((retval = driver_register (&driver->driver)) != 0) 784efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern goto err_register; 785efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if ((retval = device_bind_driver (&dum->gadget.dev)) != 0) 786efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern goto err_bind_driver; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* khubd will enumerate this in a while */ 789f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock_irq (&dum->lock); 790f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = 1; 791f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 792f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock_irq (&dum->lock); 793685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern 794685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern usb_hcd_poll_rh_status (dummy_to_hcd (dum)); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 796efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern 797efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_bind_driver: 798efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern driver_unregister (&driver->driver); 799efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_register: 8006bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell if (driver->unbind) 8016bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell driver->unbind (&dum->gadget); 802efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern spin_lock_irq (&dum->lock); 803efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern dum->pullup = 0; 804efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern set_link_state (dum); 805efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern spin_unlock_irq (&dum->lock); 806efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_bind_gadget: 807efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern dum->driver = NULL; 808efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern dum->gadget.dev.driver = NULL; 809efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern return retval; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_register_driver); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_unregister_driver (struct usb_gadget_driver *driver) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = the_controller; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 8216bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell if (!driver || driver != dum->driver || !driver->unbind) 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 824d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 828f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = 0; 829f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->unbind (&dum->gadget); 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = NULL; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_release_driver (&dum->gadget.dev); 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister (&driver->driver); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 838f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_lock_irqsave (&dum->lock, flags); 839f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = 0; 840f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 841f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern spin_unlock_irqrestore (&dum->lock, flags); 842f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 843685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern usb_hcd_poll_rh_status (dummy_to_hcd (dum)); 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_unregister_driver); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 850cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern/* just declare this in any driver that really need it */ 851cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternextern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); 852cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSYS; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (net2280_set_fifo_mode); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 859d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 860d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be 861d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */ 862d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void 863d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev) 864d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 865d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern struct dummy *dum = gadget_dev_to_dummy (dev); 866d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 8671720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern usb_put_hcd (dummy_to_hcd (dum)); 868d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 869d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 8708364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev) 871d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 872d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern struct dummy *dum = the_controller; 873d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern int rc; 874d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 875d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.name = gadget_name; 876d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.ops = &dummy_ops; 877d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.is_dualspeed = 1; 878d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 879d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern /* maybe claim OTG support, though we won't complete HNP */ 880d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); 881d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 882d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern strcpy (dum->gadget.dev.bus_id, "gadget"); 8838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dum->gadget.dev.parent = &pdev->dev; 884d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.dev.release = dummy_gadget_release; 885d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern rc = device_register (&dum->gadget.dev); 886d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (rc < 0) 887d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 888d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 8891720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern usb_get_hcd (dummy_to_hcd (dum)); 890d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 8918364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern platform_set_drvdata (pdev, dum); 892efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern rc = device_create_file (&dum->gadget.dev, &dev_attr_function); 893efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if (rc < 0) 894efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern device_unregister (&dum->gadget.dev); 895d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 896d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 897d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 8988364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev) 899d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 9008364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern struct dummy *dum = platform_get_drvdata (pdev); 901d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9028364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern platform_set_drvdata (pdev, NULL); 903d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern device_remove_file (&dum->gadget.dev, &dev_attr_function); 904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern device_unregister (&dum->gadget.dev); 905d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 906d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) 909391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 9108364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern struct dummy *dum = platform_get_drvdata(pdev); 911391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9128364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_dbg (&pdev->dev, "%s\n", __FUNCTION__); 913391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_lock_irq (&dum->lock); 914391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->udc_suspended = 1; 915391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern set_link_state (dum); 916391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_unlock_irq (&dum->lock); 917391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9188364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern pdev->dev.power.power_state = state; 919391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_poll_rh_status (dummy_to_hcd (dum)); 920391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 921391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 922391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9238364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_resume (struct platform_device *pdev) 924391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 9258364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern struct dummy *dum = platform_get_drvdata(pdev); 926391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9278364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_dbg (&pdev->dev, "%s\n", __FUNCTION__); 928391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_lock_irq (&dum->lock); 929391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->udc_suspended = 0; 930391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern set_link_state (dum); 931391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_unlock_irq (&dum->lock); 932391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9338364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern pdev->dev.power.power_state = PMSG_ON; 934391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_poll_rh_status (dummy_to_hcd (dum)); 935391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 936391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 9383ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = { 939d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_udc_probe, 940d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_udc_remove, 941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_udc_suspend, 942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_udc_resume, 9433ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 9443ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) gadget_name, 9453ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 9463ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 947d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 948d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers. 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller. 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback. that callback connects writes from 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules. 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue ( 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb, 96655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 971e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb->transfer_buffer && urb->transfer_buffer_length) 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp = kmalloc (sizeof *urbp, mem_flags); 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urbp) 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp->urb = urb; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 983e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_link_urb_to_ep(hcd, urb); 984e9df41c5c5899259541dc928872cad4d07b82076Alan Stern if (rc) { 985e9df41c5c5899259541dc928872cad4d07b82076Alan Stern kfree(urbp); 986e9df41c5c5899259541dc928872cad4d07b82076Alan Stern goto done; 987e9df41c5c5899259541dc928872cad4d07b82076Alan Stern } 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->udev) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->udev = urb->dev; 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_get_dev (dum->udev); 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (unlikely (dum->udev != urb->dev)) 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), "usb_device address has changed!\n"); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&urbp->urbp_list, &dum->urbp_list); 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->hcpriv = urbp; 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipetype (urb->pipe) == PIPE_CONTROL) 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 1; /* mark as a new urb */ 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kick the scheduler, it'll do the rest */ 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!timer_pending (&dum->timer)) 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer (&dum->timer, jiffies + 1); 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 1005e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done: 1006e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1009e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1011391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct dummy *dum; 1012391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned long flags; 1013e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 1014391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1015391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* giveback happens automatically in timer callback, 1016391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern * so make sure the callback happens */ 1017391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum = hcd_to_dummy (hcd); 1018391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_lock_irqsave (&dum->lock, flags); 1019e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1020e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_check_unlink_urb(hcd, urb, status); 1021e9df41c5c5899259541dc928872cad4d07b82076Alan Stern if (!rc && dum->rh_state != DUMMY_RH_RUNNING && 1022e9df41c5c5899259541dc928872cad4d07b82076Alan Stern !list_empty(&dum->urbp_list)) 1023391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern mod_timer (&dum->timer, jiffies); 1024e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1025391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_unlock_irqrestore (&dum->lock, flags); 1026e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */ 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 10314d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, 10324d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern int *status) 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop: 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if there's no request queued, the device is NAKing; return */ 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned host_len, dev_len, len; 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int is_short, to_host; 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rescan = 0; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1..N packets of ep->ep.maxpacket each ... the last one 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be short (including zero length). 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * writer can send a zlp explicitly (length 0) or implicitly 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (length mod maxpacket zero, and 'zero' flag); they always 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * terminate reads. 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_len = urb->transfer_buffer_length - urb->actual_length; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_len = req->req.length - req->req.actual; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (host_len, dev_len); 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME update emulated data toggle too */ 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_host = usb_pipein (urb->pipe); 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely (len == 0)) 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = 1; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ubuf, *rbuf; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not enough bandwidth left? */ 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (limit < ep->ep.maxpacket && limit < len) 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (len, (unsigned) limit); 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use an extra pass for the final short packet */ 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > ep->ep.maxpacket) { 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= (len % ep->ep.maxpacket); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = (len % ep->ep.maxpacket) != 0; 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* else transfer packet(s) */ 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ubuf = urb->transfer_buffer + urb->actual_length; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rbuf = req->req.buf + req->req.actual; 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (to_host) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (ubuf, rbuf, len); 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (rbuf, ubuf, len); 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit -= len; 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length += len; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.actual += len; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* short packets terminate, maybe with overflow/underflow. 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's only really an error to write too much. 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partially filling a buffer optionally blocks queue advances 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (so completion handlers can clean up the queue) but we don't 1095b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern * need to emulate such data-in-flight. 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_short) { 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len == dev_len) { 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 11004d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (to_host) { 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev_len > host_len) 11044d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = -EOVERFLOW; 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11064d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!to_host) { 11084d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len > dev_len) 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* many requests terminate without a short packet */ 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.length == req->req.actual 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !req->req.zero) 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length == urb->actual_length 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !(urb->transfer_flags 11224d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern & URB_ZERO_PACKET)) 11234d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device side completion --> continuable */ 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.status != -EINPROGRESS) { 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* requests might have been unlinked... */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* host side completion --> terminate */ 11394d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (*status != -EINPROGRESS) 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* rescan to continue with any other queued i/o */ 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rescan) 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto top; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit = ep->ep.maxpacket; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->gadget.speed == USB_SPEED_HIGH) { 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* high bandwidth mode */ 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = le16_to_cpu(ep->desc->wMaxPacketSize); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (tmp >> 11) & 0x03; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp *= 8 /* applies to entire frame */; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit += limit * tmp; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_active(dum) ((dum->port_status & \ 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_SUSPEND)) \ 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_active (dum)) 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((address & ~USB_DIR_IN) == 0) 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &dum->ep [0]; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < DUMMY_ENDPOINTS; i++) { 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = &dum->ep [i]; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep->desc) 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc->bEndpointAddress == address) 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ep; 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest (Dev_Request | USB_DIR_IN) 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest (Intf_Request | USB_DIR_IN) 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest (Ep_Request | USB_DIR_IN) 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq(). 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_timer (unsigned long _dum) 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = (struct dummy *) _dum; 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp, *tmp; 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit, total; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* simplistic model for one frame's bandwidth */ 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 8/*bytes*/ * 12/*packets*/; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 64/*bytes*/ * 19/*packets*/; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), "bogus device speed\n"); 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME if HZ != 1000 this will probably misbehave ... */ 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look at each urb queued by the host side driver */ 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->udev) { 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "timer fired with no URBs pending?\n"); 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep_name [i]) 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->ep [i].already_seen = 0; 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart: 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) { 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 address; 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = NULL; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 12504d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern int status = -EINPROGRESS; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = urbp->urb; 1253eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern if (urb->unlinked) 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 1255eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern else if (dum->rh_state != DUMMY_RH_RUNNING) 1256391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern continue; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = usb_pipetype (urb->pipe); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* used up this frame's non-periodic bandwidth? 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME there's infinite bandwidth for control and 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * periodic transfers ... unrealistic. 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total <= 0 && type == PIPE_BULK) 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the gadget's ep for this request (if configured) */ 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address = usb_pipeendpoint (urb->pipe); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipein (urb->pipe)) 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address |= USB_DIR_IN; 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = find_endpoint(dum, address); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) { 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set_configuration() disagreement */ 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no ep configured for urb %p\n", 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb); 12764d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPROTO; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->already_seen) 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 1; 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && urb->error_count) { 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 1; /* a new urb */ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 0; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->halted && !ep->setup_stage) { 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE: must not be iso! */ 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name, urb); 12914d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME make sure both ends agree on maxpacket */ 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* handle control requests */ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && ep->setup_stage) { 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ctrlrequest setup; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = 1; 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep2; 1301cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern unsigned w_index; 1302cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern unsigned w_value; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = *(struct usb_ctrlrequest*) urb->setup_packet; 1305cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern w_index = le16_to_cpu(setup.wIndex); 1306cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern w_value = le16_to_cpu(setup.wValue); 1307cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern if (le16_to_cpu(setup.wLength) != 1308cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern urb->transfer_buffer_length) { 13094d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EOVERFLOW; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* paranoia, in case of stale queued data */ 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 1317d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "stale req = %p\n", 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 0; 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver never sees set_address or operations 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on standard feature flags. some hardware doesn't 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even expose them. 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 0; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (setup.bRequest) { 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_ADDRESS: 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType != Dev_Request) 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1338cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern dum->address = w_value; 13394d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 1340d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), "set_address = %d\n", 1341cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern w_value); 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_FEATURE: 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_Request) { 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 1347cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern switch (w_value) { 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DEVICE_REMOTE_WAKEUP: 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13505742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_B_HNP_ENABLE: 13515742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.b_hnp_enable = 1; 13525742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 13535742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_A_HNP_SUPPORT: 13545742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.a_hnp_support = 1; 13555742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 13565742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_A_ALT_HNP_SUPPORT: 13575742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.a_alt_hnp_support 13585742b0c95026c817d9c266174ca39a909e8d38caAlan Stern = 1; 13595742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == 0) { 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= 1365cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern (1 << w_value); 13664d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == Ep_Request) { 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint halt 1371cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern ep2 = find_endpoint (dum, w_index); 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2->halted = 1; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 13784d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_CLEAR_FEATURE: 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_Request) { 1383cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern switch (w_value) { 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DEVICE_REMOTE_WAKEUP: 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DEVICE_REMOTE_WAKEUP); 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 13884d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == Ep_Request) { 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint halt 1396cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern ep2 = find_endpoint (dum, w_index); 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2->halted = 0; 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 14034d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_STATUS: 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_InRequest 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || setup.bRequestType 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == Intf_InRequest 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || setup.bRequestType 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == Ep_InRequest 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ) { 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // device: remote wakeup, selfpowered 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // interface: nothing 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint: halt 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (char *)urb->transfer_buffer; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length > 0) { 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Ep_InRequest) { 1422cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern ep2 = find_endpoint (dum, w_index); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = ep2->halted; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Dev_InRequest) { 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = (u8) 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus; 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = 0; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length > 1) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [1] = 0; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = min (2, 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->transfer_buffer_length); 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 14404d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = 0; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver handles all other requests. block 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until setup() returns; no reentrancy issues etc. 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 0) { 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = dum->driver->setup (&dum->gadget, 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &setup); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= 0) { 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no delays (max 64KB data stage) */ 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 64*1024; 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto treat_control_like_bulk; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error, see below */ 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value < 0) { 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value != -EOPNOTSUPP) 1464d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dev_dbg (udc_dev(dum), 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "setup --> %d\n", 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value); 14674d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = 0; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non-control requests */ 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = total; 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_ISOCHRONOUS: 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use urb->iso_frame_desc[i]. 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete whether or not ep has requests queued. 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * report random errors, to debug drivers. 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 14844d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -ENOSYS; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this almost certainly polls too fast. 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // case PIPE_BULK: case PIPE_CONTROL: 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds treat_control_like_bulk: 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 14984d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern total = transfer(dum, urb, ep, limit, &status); 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* incomplete transfer? */ 15034d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (status == -EINPROGRESS) 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb: 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&urbp->urbp_list); 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (urbp); 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep) 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = ep->setup_stage = 0; 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1512e9df41c5c5899259541dc928872cad4d07b82076Alan Stern usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 15144d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern urb->status = status; 151528431146993e0ab3a2a592af8541543fe0cc2c8eAl Viro usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if (list_empty (&dum->urbp_list)) { 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_dev (dum->udev); 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->udev = NULL; 1524391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern } else if (dum->rh_state == DUMMY_RH_RUNNING) { 1525391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* want a 1 msec delay here */ 1526391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \ 1535c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern ((USB_PORT_STAT_C_CONNECTION \ 1536c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_ENABLE \ 1537c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_SUSPEND \ 1538c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_OVERCURRENT \ 1539c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_RESET) << 16) 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf) 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1545391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern int retval = 0; 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 15503cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) 1551391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern goto done; 1552f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1553f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { 1554f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1555f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status &= ~USB_PORT_STAT_SUSPEND; 1556f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 1557f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 1558f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1559391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if ((dum->port_status & PORT_C_MASK) != 0) { 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = (1 << 1); 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", 1562391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->port_status); 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 1; 1564391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern if (dum->rh_state == DUMMY_RH_SUSPENDED) 1565391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_resume_root_hub (hcd); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1567391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone: 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc) 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (desc, 0, sizeof *desc); 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescriptorType = 0x29; 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescLength = 9; 1578cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern desc->wHubCharacteristics = (__force __u16) 1579cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern (__constant_cpu_to_le16 (0x0001)); 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bNbrPorts = 1; 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bitmap [0] = 0xff; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bitmap [1] = 0xff; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control ( 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 typeReq, 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wValue, 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wIndex, 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wLength 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15973cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) 1598391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ETIMEDOUT; 1599391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (typeReq) { 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearHubFeature: 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearPortFeature: 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 1608c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern if (dum->port_status & USB_PORT_STAT_SUSPEND) { 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20msec resume signaling */ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 1; 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = jiffies + 1612f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern msecs_to_jiffies(20); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 1616f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->port_status & USB_PORT_STAT_POWER) 1617f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dev_dbg (dummy_dev(dum), "power-off\n"); 1618f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(1 << wValue); 1621f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubDescriptor: 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hub_descriptor ((struct usb_hub_descriptor *) buf); 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubStatus: 1628cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern *(__le32 *) buf = __constant_cpu_to_le32 (0); 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetPortStatus: 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wIndex != 1) 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resets or resumes must GetPortStatus to 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete it!! 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1637f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->resuming && 1638f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern time_after_eq (jiffies, dum->re_timeout)) { 1639c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1640c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern dum->port_status &= ~USB_PORT_STAT_SUSPEND; 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1642f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && 1643f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern time_after_eq (jiffies, dum->re_timeout)) { 1644c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern dum->port_status |= (USB_PORT_STAT_C_RESET << 16); 1645c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern dum->port_status &= ~USB_PORT_STAT_RESET; 1646f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->pullup) { 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= USB_PORT_STAT_ENABLE; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* give it the best speed we agree on */ 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.speed = dum->driver->speed; 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0->maxpacket = 64; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_HIGH_SPEED; 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0->maxpacket = 8; 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_LOW_SPEED; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.speed = USB_SPEED_FULL; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1667f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 1668cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); 1669cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetHubFeature: 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetPortFeature: 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 1677f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (dum->active) { 1678c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern dum->port_status |= USB_PORT_STAT_SUSPEND; 1679f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1680f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* HNP would happen here; for now we 1681f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern * assume b_bus_req is always true. 1682f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern */ 1683f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 1684f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (((1 << USB_DEVICE_B_HNP_ENABLE) 1685f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern & dum->devstatus) != 0) 1686f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dev_dbg (dummy_dev(dum), 16875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern "no HNP yet!\n"); 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1690f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern case USB_PORT_FEAT_POWER: 1691f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= USB_PORT_STAT_POWER; 1692f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 1693f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern break; 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_RESET: 1695f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* if it's already enabled, disable */ 1696f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status &= ~(USB_PORT_STAT_ENABLE 1697f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_LOW_SPEED 1698f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_HIGH_SPEED); 1699391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->devstatus = 0; 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50msec reset signaling */ 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = jiffies + msecs_to_jiffies(50); 1702f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1704f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { 1705f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->port_status |= (1 << wValue); 1706f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern set_link_state (dum); 1707f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "hub control req%04x v%04x i%04x l%d\n", 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds typeReq, wValue, wIndex, wLength); 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* "protocol stall" on error */ 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 1720685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern 1721685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern if ((dum->port_status & PORT_C_MASK) != 0) 1722685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern usb_hcd_poll_rh_status (hcd); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17260c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd) 1727391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1728391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct dummy *dum = hcd_to_dummy (hcd); 1729391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 17303cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__); 17313cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 1732391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_lock_irq (&dum->lock); 1733391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->rh_state = DUMMY_RH_SUSPENDED; 1734391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern set_link_state (dum); 17353cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_SUSPENDED; 1736391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_unlock_irq (&dum->lock); 1737391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1738391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1739391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 17400c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd) 1741391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1742391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct dummy *dum = hcd_to_dummy (hcd); 17433cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 17443cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 17453cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__); 1746391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1747391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_lock_irq (&dum->lock); 17483cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { 1749cfa59dab27d1b282886e7772a8f9548236883892Alan Stern rc = -ESHUTDOWN; 17503cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else { 17513cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dum->rh_state = DUMMY_RH_RUNNING; 17523cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern set_link_state (dum); 17533cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern if (!list_empty(&dum->urbp_list)) 17543cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern mod_timer (&dum->timer, jiffies); 17553cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_RUNNING; 17563cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } 1757391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern spin_unlock_irq (&dum->lock); 17583cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 1759391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb) 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ep = usb_pipeendpoint (urb->pipe); 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return snprintf (buf, size, 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "urb/%p %s ep%d%s%s len %d/%d\n", 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb, 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->dev->speed) { 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: s = "ls"; break; 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: s = "fs"; break; 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: s = "hs"; break; 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: s = "?"; break; 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s; }), 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; \ 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { \ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_CONTROL: s = ""; break; \ 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_BULK: s = "-bulk"; break; \ 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: s = "-int"; break; \ 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: s = "-iso"; break; \ 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s;}), 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length, urb->transfer_buffer_length); 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 179010523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf) 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd = dev_get_drvdata (dev); 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = hcd_to_dummy (hcd); 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = 0; 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t temp; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += temp; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size += temp; 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_start (struct usb_hcd *hcd) 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER side init ... we emulate a root hub that'll only ever 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * talk to one device (the slave side). Also appears in sysfs, 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just like more familiar pci-based HCDs. 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init (&dum->lock); 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer (&dum->timer); 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->timer.function = dummy_timer; 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->timer.data = (unsigned long) dum; 1827391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern dum->rh_state = DUMMY_RH_RUNNING; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&dum->urbp_list); 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern /* only show a low-power port: just 8mA */ 1832bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern hcd->power_budget = 8; 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd->state = HC_STATE_RUNNING; 1834685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern hcd->uses_new_polling = 1; 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18365742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG 18375742b0c95026c817d9c266174ca39a909e8d38caAlan Stern hcd->self.otg_port = 1; 18385742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif 18395742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 1841efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern return device_create_file (dummy_dev(dum), &dev_attr_urbs); 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd) 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file (dummy_dev(dum), &dev_attr_urbs); 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver (dum->driver); 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info (dummy_dev(dum), "stopped\n"); 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd) 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dummy_g_get_frame (NULL); 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct hc_driver dummy_hcd = { 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = (char *) driver_name, 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .product_desc = "Dummy host controller", 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hcd_priv_size = sizeof(struct dummy), 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flags = HCD_USB2, 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = dummy_start, 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = dummy_stop, 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_enqueue = dummy_urb_enqueue, 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_dequeue = dummy_urb_dequeue, 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame_number = dummy_h_get_frame, 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_status_data = dummy_hub_status, 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_control = dummy_hub_control, 18790c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_suspend = dummy_bus_suspend, 18800c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_resume = dummy_bus_resume, 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev) 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd; 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18888364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18908364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, pdev->dev.bus_id); 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!hcd) 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = hcd_to_dummy (hcd); 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_add_hcd(hcd, 0, 0); 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 0) { 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_hcd (hcd); 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = NULL; 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19038364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_remove (struct platform_device *pdev) 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd; 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19078364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern hcd = platform_get_drvdata (pdev); 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_remove_hcd (hcd); 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_hcd (hcd); 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = NULL; 1911d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19148364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state) 1915391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1916391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 19173cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern struct dummy *dum; 19183cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 1919391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19208364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_dbg (&pdev->dev, "%s\n", __FUNCTION__); 1921391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19223cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd = platform_get_drvdata (pdev); 19233cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dum = hcd_to_dummy (hcd); 19243cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern if (dum->rh_state == DUMMY_RH_RUNNING) { 19253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); 19263cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern rc = -EBUSY; 19273cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else 19283cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 19293cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 1930391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1931391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19328364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev) 1933391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1934391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 1935391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19368364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_dbg (&pdev->dev, "%s\n", __FUNCTION__); 1937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19383cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd = platform_get_drvdata (pdev); 19393cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 1940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern usb_hcd_poll_rh_status (hcd); 1941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1943391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 19443ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = { 1945d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_hcd_probe, 1946d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_hcd_remove, 1947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_hcd_suspend, 1948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_hcd_resume, 19493ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 19503ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) driver_name, 19513ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 19523ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 1953d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1955d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1957d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* These don't need to do anything because the pdev structures are 1958d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * statically allocated. */ 1959d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void 1960d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_udc_release (struct device *dev) {} 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1962d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void 1963d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_hcd_release (struct device *dev) {} 1964d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1965d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device the_udc_pdev = { 1966d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .name = (char *) gadget_name, 1967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .id = -1, 1968d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .dev = { 1969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .release = dummy_udc_release, 1970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern }, 1971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1973d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device the_hcd_pdev = { 1974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .name = (char *) driver_name, 1975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .id = -1, 1976d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .dev = { 1977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .release = dummy_hcd_release, 1978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern }, 1979d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void) 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_disabled ()) 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1987d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 19883ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King retval = platform_driver_register (&dummy_hcd_driver); 1989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 1991d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 19923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King retval = platform_driver_register (&dummy_udc_driver); 1993d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 1994d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern goto err_register_udc_driver; 1995d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern retval = platform_device_register (&the_hcd_pdev); 1997d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 1998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern goto err_register_hcd; 1999d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern retval = platform_device_register (&the_udc_pdev); 2001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern goto err_register_udc; 2003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return retval; 2004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2005d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc: 2006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern platform_device_unregister (&the_hcd_pdev); 2007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_hcd: 20083ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister (&dummy_udc_driver); 2009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver: 20103ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister (&dummy_hcd_driver); 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init); 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void) 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2017d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern platform_device_unregister (&the_udc_pdev); 2018d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern platform_device_unregister (&the_hcd_pdev); 20193ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister (&dummy_udc_driver); 20203ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister (&dummy_hcd_driver); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup); 2023