dummy_hcd.c revision 5742b0c95026c817d9c266174ca39a909e8d38ca
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#define DEBUG 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp_lock.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/version.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_gadget.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../core/hcd.h" 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Host+Gadget Emulator" 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "17 Dec 2004" 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char driver_name [] = "dummy_hcd"; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char driver_desc [] = "USB Host+Gadget Emulator"; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char gadget_name [] = "dummy_udc"; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell"); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL"); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep { 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_io; /* jiffies timestamp */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *desc; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep ep; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned halted : 1; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned already_seen : 1; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned setup_stage : 1; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; /* ep's requests */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request req; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_ep, struct dummy_ep, ep); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_request *_req) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (_req, struct dummy_request, req); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints, 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types: 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * number can be changed. Names like "ep-a" are used for this type. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Fixed Function: in other cases. some characteristics may be mutable; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that'd be hardware-specific. Names like "ep12out-bulk" are used. 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on. 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0"; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0name, /* everyone has ep0 */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* act like a net2280: high speed, six configurable endpoints */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like pxa250: fifteen fixed function endpoints */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep15in-int", 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like sa1100: two fixed function endpoints */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1out-bulk", "ep2in-bulk", 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE 64 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy { 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE/GADGET side support 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep ep [DUMMY_ENDPOINTS]; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget gadget; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget_driver *driver; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request fifo_req; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fifo_buf [FIFO_SIZE]; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 devstatus; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER/HOST side support 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timer_list timer; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 port_status; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned resuming:1; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long re_timeout; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *udev; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (struct dummy *) (hcd->hcd_priv); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct usb_hcd *dummy_to_hcd (struct dummy *dum) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of((void *) dum, struct usb_hcd, hcd_priv); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct device *dummy_dev (struct dummy *dum) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dummy_to_hcd(dum)->self.controller; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (ep->gadget, struct dummy, gadget); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (gadget, struct dummy, gadget); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of (dev, struct dummy, gadget.dev); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy *the_controller; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This "hardware" may look a bit odd in diagnostics since it's got both 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * host and device sides; and it binds different drivers to each side. 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct platform_device the_pdev; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct device_driver dummy_driver = { 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = (char *) driver_name, 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bus = &platform_bus_type, 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state. All the work is done when the host 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation. Real device controller 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc. 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dum->port_status & USB_PORT_STAT_ENABLE) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !desc || ep->desc || _ep->name == ep0name 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || desc->bDescriptorType != USB_DT_ENDPOINT) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !is_enabled (dum)) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* drivers must not request bad settings, since lower levels 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (hardware or its drivers) may not check. some endpoints 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't do iso, many have maxpacket limitations, etc. 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since this "hardware" driver is here to help debugging, we 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have some extra sanity checks. (there could be more though, 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * especially for "ep9out" style fixed function ones.) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso") 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) { 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max == 512) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* conserve return statements */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (max) { 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: case 16: case 32: case 64: 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we'll fake any legal size */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 64) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 8) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strstr (ep->ep.name, "-bulk") 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || strstr (ep->ep.name, "-int")) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1023) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* few chips support control except on ep0 */ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->maxpacket = max; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = desc; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->name, 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bEndpointAddress & 0x0f, 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *val; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (desc->bmAttributes & 0x03) { 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: val = "intr"; break; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: val = "ctrl"; break; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; val; }), 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* at this point real hardware should be NAKing transfers 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to that endpoint, until a buffer is queued to it. 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called with spinlock held */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nuke (struct dummy *dum, struct dummy_ep *ep) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!list_empty (&ep->queue)) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = list_entry (ep->queue.next, struct dummy_request, queue); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -ESHUTDOWN; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !ep->desc || _ep->name == ep0name) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nuke (dum, ep); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request * 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_alloc_request (struct usb_ep *_ep, int mem_flags) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = kmalloc (sizeof *req, mem_flags); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (req, 0, sizeof *req); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&req->queue); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &req->req; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON (!list_empty (&req->queue)); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (req); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void * 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_alloc_buffer ( 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *_ep, 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned bytes, 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t *dma, 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mem_flags 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *retval; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = kmalloc (bytes, mem_flags); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dma = (dma_addr_t) retval; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_buffer ( 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *_ep, 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *buf, 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dma, 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned bytes 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (buf); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = usb_request_to_dummy_request (_req); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_req || !list_empty (&req->queue) || !_req->complete) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || (!ep->desc && _ep->name != ep0name)) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !is_enabled (dum)) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, _req, _ep->name, _req->length, _req->buf); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -EINPROGRESS; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = 0; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* implement an emulated single-request FIFO */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&dum->fifo_req.queue) && 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_empty (&ep->queue) && 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->length <= FIFO_SIZE) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = &dum->fifo_req; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req = *_req; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.buf = dum->fifo_buf; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (dum->fifo_buf, _req->buf, _req->length); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.context = dum; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete = fifo_complete; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = _req->length; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = 0; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&req->queue, &ep->queue); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware would likely enable transfers here, in case 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it'd been left NAKing. 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = -EINVAL; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req = NULL; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !_req) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (&req->req == _req) { 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -ECONNRESET; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dequeued req %p from %s, len %d buf %p\n", 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req, _ep->name, _req->length, _req->buf); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->complete (_ep, _req); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_set_halt (struct usb_ep *_ep, int value) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_to_dummy_ep (_ep); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = ep_to_dummy (ep); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!value) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !list_empty (&ep->queue)) 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 1; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME clear emulated data toggle too */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable = dummy_enable, 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disable = dummy_disable, 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .alloc_request = dummy_alloc_request, 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .free_request = dummy_free_request, 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .alloc_buffer = dummy_alloc_buffer, 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .free_buffer = dummy_free_buffer, 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* map, unmap, ... eventually hook the "generic" dma calls */ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queue = dummy_queue, 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = dummy_dequeue, 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_halt = dummy_set_halt, 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timeval tv; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_gettimeofday (&tv); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tv.tv_usec / 1000; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = gadget_to_dummy (_gadget); 6045742b0c95026c817d9c266174ca39a909e8d38caAlan Stern if (!(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) 6055742b0c95026c817d9c266174ca39a909e8d38caAlan Stern || !(dum->devstatus & 6065742b0c95026c817d9c266174ca39a909e8d38caAlan Stern ( (1 << USB_DEVICE_B_HNP_ENABLE) 6075742b0c95026c817d9c266174ca39a909e8d38caAlan Stern | (1 << USB_DEVICE_REMOTE_WAKEUP)))) 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* hub notices our request, issues downstream resume, etc */ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 1; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = gadget_to_dummy (_gadget); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value) 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = { 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame = dummy_g_get_frame, 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wakeup = dummy_wakeup, 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_selfpowered = dummy_set_selfpowered, 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 63810523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = gadget_dev_to_dummy (dev); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !dum->driver->function) 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDEVICE_ATTR (function, S_IRUGO, show_function, NULL); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration. 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work. So most implementations of these api calls will rely on the 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware. But curious 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption. 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers: just add to a big root hub. 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_udc_release (struct device *dev) 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_pdev_release (struct device *dev) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_register_udc (struct dummy *dum) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy (dum->gadget.dev.bus_id, "udc"); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.parent = dummy_dev(dum); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.release = dummy_udc_release; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = device_register (&dum->gadget.dev); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == 0) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file (&dum->gadget.dev, &dev_attr_function); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_unregister_udc (struct dummy *dum) 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file (&dum->gadget.dev, &dev_attr_function); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_unregister (&dum->gadget.dev); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_register_driver (struct usb_gadget_driver *driver) 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = the_controller; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, i; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver) 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!driver->bind || !driver->unbind || !driver->setup 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || driver->speed == USB_SPEED_UNKNOWN) 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE side init ... the layer above hardware, which 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't enumerate without help from the driver we're binding. 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.name = gadget_name; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ops = &dummy_ops; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.is_dualspeed = 1; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7185742b0c95026c817d9c266174ca39a909e8d38caAlan Stern /* maybe claim OTG support, though we won't complete HNP */ 7195742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); 7205742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus = 0; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 0; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&dum->gadget.ep_list); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = &dum->ep [i]; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep_name [i]) 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name = ep_name [i]; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.ops = &dummy_ep_ops; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = ep->already_seen = ep->setup_stage = 0; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.maxpacket = ~0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->gadget = &dum->gadget; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&ep->queue); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0 = &dum->ep [0].ep; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->ep [0].ep.maxpacket = 64; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&dum->ep [0].ep.ep_list); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&dum->fifo_req.queue); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = driver; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.driver = &driver->driver; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n", 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = driver->bind (&dum->gadget)) != 0) { 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = NULL; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.dev.driver = NULL; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // FIXME: Check these calls for errors and re-order 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.bus = dum->gadget.dev.parent->bus; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_register (&driver->driver); 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_bind_driver (&dum->gadget.dev); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* khubd will enumerate this in a while */ 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= USB_PORT_STAT_CONNECTION 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (1 << USB_PORT_FEAT_C_CONNECTION); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_register_driver); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold lock */ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstop_activity (struct dummy *dum, struct usb_gadget_driver *driver) 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* prevent any more requests */ 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->address = 0; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The timer is left running so that outstanding URBs can fail */ 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* nuke any pending requests first, so driver i/o is quiesced */ 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nuke (dum, ep); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* driver now does any non-usb quiescing necessary */ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (driver) { 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->disconnect (&dum->gadget); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_unregister_driver (struct usb_gadget_driver *driver) 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = the_controller; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum) 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!driver || driver != dum->driver) 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n", 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stop_activity (dum, driver); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->unbind (&dum->gadget); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = NULL; 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_release_driver (&dum->gadget.dev); 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister (&driver->driver); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_unregister_driver); 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSYS; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (net2280_set_fifo_mode); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers. 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller. 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback. that callback connects writes from 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules. 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue ( 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_host_endpoint *ep, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb, 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mem_flags 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb->transfer_buffer && urb->transfer_buffer_length) 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp = kmalloc (sizeof *urbp, mem_flags); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urbp) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp->urb = urb; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->udev) { 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->udev = urb->dev; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_get_dev (dum->udev); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (unlikely (dum->udev != urb->dev)) 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), "usb_device address has changed!\n"); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail (&urbp->urbp_list, &dum->urbp_list); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->hcpriv = urbp; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipetype (urb->pipe) == PIPE_CONTROL) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 1; /* mark as a new urb */ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kick the scheduler, it'll do the rest */ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!timer_pending (&dum->timer)) 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer (&dum->timer, jiffies + 1); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* giveback happens automatically in timer callback */ 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void maybe_set_status (struct urb *urb, int status) 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&urb->lock); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status == -EINPROGRESS) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->status = status; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&urb->lock); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstransfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop: 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if there's no request queued, the device is NAKing; return */ 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned host_len, dev_len, len; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int is_short, to_host; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rescan = 0; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1..N packets of ep->ep.maxpacket each ... the last one 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be short (including zero length). 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * writer can send a zlp explicitly (length 0) or implicitly 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (length mod maxpacket zero, and 'zero' flag); they always 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * terminate reads. 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_len = urb->transfer_buffer_length - urb->actual_length; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_len = req->req.length - req->req.actual; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (host_len, dev_len); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME update emulated data toggle too */ 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_host = usb_pipein (urb->pipe); 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely (len == 0)) 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = 1; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ubuf, *rbuf; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not enough bandwidth left? */ 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (limit < ep->ep.maxpacket && limit < len) 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min (len, (unsigned) limit); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use an extra pass for the final short packet */ 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > ep->ep.maxpacket) { 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= (len % ep->ep.maxpacket); 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = (len % ep->ep.maxpacket) != 0; 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* else transfer packet(s) */ 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ubuf = urb->transfer_buffer + urb->actual_length; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rbuf = req->req.buf + req->req.actual; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (to_host) 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (ubuf, rbuf, len); 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (rbuf, ubuf, len); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit -= len; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length += len; 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.actual += len; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* short packets terminate, maybe with overflow/underflow. 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's only really an error to write too much. 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partially filling a buffer optionally blocks queue advances 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (so completion handlers can clean up the queue) but we don't 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to emulate such data-in-flight. so we only show part 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the URB_SHORT_NOT_OK effect: completion status. 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_short) { 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len == dev_len) { 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (to_host) { 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev_len > host_len) 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -EOVERFLOW); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (urb->transfer_flags 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & URB_SHORT_NOT_OK) 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? -EREMOTEIO : 0); 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!to_host) { 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len > dev_len) 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* many requests terminate without a short packet */ 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.length == req->req.actual 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !req->req.zero) 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length == urb->actual_length 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !(urb->transfer_flags 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & URB_ZERO_PACKET)) { 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device side completion --> continuable */ 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.status != -EINPROGRESS) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* requests might have been unlinked... */ 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* host side completion --> terminate */ 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status != -EINPROGRESS) 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* rescan to continue with any other queued i/o */ 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rescan) 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto top; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit = ep->ep.maxpacket; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->gadget.speed == USB_SPEED_HIGH) { 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* high bandwidth mode */ 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = le16_to_cpu(ep->desc->wMaxPacketSize); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = le16_to_cpu (tmp); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (tmp >> 11) & 0x03; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp *= 8 /* applies to entire frame */; 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit += limit * tmp; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_active(dum) ((dum->port_status & \ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_SUSPEND)) \ 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_active (dum)) 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((address & ~USB_DIR_IN) == 0) 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &dum->ep [0]; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < DUMMY_ENDPOINTS; i++) { 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = &dum->ep [i]; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep->desc) 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc->bEndpointAddress == address) 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ep; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest (Dev_Request | USB_DIR_IN) 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest (Intf_Request | USB_DIR_IN) 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest (Ep_Request | USB_DIR_IN) 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq(). 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_timer (unsigned long _dum) 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = (struct dummy *) _dum; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp, *tmp; 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit, total; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* simplistic model for one frame's bandwidth */ 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 8/*bytes*/ * 12/*packets*/; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 64/*bytes*/ * 19/*packets*/; 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), "bogus device speed\n"); 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME if HZ != 1000 this will probably misbehave ... */ 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look at each urb queued by the host side driver */ 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->udev) { 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err (dummy_dev(dum), 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "timer fired with no URBs pending?\n"); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep_name [i]) 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->ep [i].already_seen = 0; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart: 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) { 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 address; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = NULL; 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = urbp->urb; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status != -EINPROGRESS) { 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* likely it was just unlinked */ 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = usb_pipetype (urb->pipe); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* used up this frame's non-periodic bandwidth? 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME there's infinite bandwidth for control and 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * periodic transfers ... unrealistic. 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total <= 0 && type == PIPE_BULK) 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the gadget's ep for this request (if configured) */ 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address = usb_pipeendpoint (urb->pipe); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_pipein (urb->pipe)) 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address |= USB_DIR_IN; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = find_endpoint(dum, address); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) { 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set_configuration() disagreement */ 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no ep configured for urb %p\n", 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb); 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -EPROTO); 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->already_seen) 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 1; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && urb->error_count) { 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 1; /* a new urb */ 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 0; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->halted && !ep->setup_stage) { 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE: must not be iso! */ 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name, urb); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -EPIPE); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME make sure both ends agree on maxpacket */ 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* handle control requests */ 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == &dum->ep [0] && ep->setup_stage) { 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ctrlrequest setup; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = 1; 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep2; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = *(struct usb_ctrlrequest*) urb->setup_packet; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpus (&setup.wIndex); 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpus (&setup.wValue); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpus (&setup.wLength); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.wLength != urb->transfer_buffer_length) { 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -EOVERFLOW); 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* paranoia, in case of stale queued data */ 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (req, &ep->queue, queue) { 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init (&req->queue); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "stale req = %p\n", 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req); 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete (&ep->ep, &req->req); 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 0; 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver never sees set_address or operations 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on standard feature flags. some hardware doesn't 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even expose them. 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 0; 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (setup.bRequest) { 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_ADDRESS: 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType != Dev_Request) 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->address = setup.wValue; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "set_address = %d\n", 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup.wValue); 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_FEATURE: 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_Request) { 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (setup.wValue) { 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DEVICE_REMOTE_WAKEUP: 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12235742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_B_HNP_ENABLE: 12245742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.b_hnp_enable = 1; 12255742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 12265742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_A_HNP_SUPPORT: 12275742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.a_hnp_support = 1; 12285742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 12295742b0c95026c817d9c266174ca39a909e8d38caAlan Stern case USB_DEVICE_A_ALT_HNP_SUPPORT: 12305742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dum->gadget.a_alt_hnp_support 12315742b0c95026c817d9c266174ca39a909e8d38caAlan Stern = 1; 12325742b0c95026c817d9c266174ca39a909e8d38caAlan Stern break; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == 0) { 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1 << setup.wValue); 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == Ep_Request) { 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint halt 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2 = find_endpoint (dum, 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup.wIndex); 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2->halted = 1; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_CLEAR_FEATURE: 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_Request) { 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (setup.wValue) { 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DEVICE_REMOTE_WAKEUP: 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DEVICE_REMOTE_WAKEUP); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == Ep_Request) { 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint halt 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2 = find_endpoint (dum, 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup.wIndex); 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2->halted = 0; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_STATUS: 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == Dev_InRequest 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || setup.bRequestType 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == Intf_InRequest 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || setup.bRequestType 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == Ep_InRequest 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ) { 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf; 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // device: remote wakeup, selfpowered 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // interface: nothing 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // endpoint: halt 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (char *)urb->transfer_buffer; 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length > 0) { 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup.bRequestType == 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Ep_InRequest) { 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep2 = find_endpoint (dum, setup.wIndex); 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep2) { 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOPNOTSUPP; 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = ep2->halted; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (setup.bRequestType == 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Dev_InRequest) { 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = (u8) 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = 0; 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length > 1) 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [1] = 0; 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = min (2, 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->transfer_buffer_length); 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = 0; 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, 0); 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver handles all other requests. block 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until setup() returns; no reentrancy issues etc. 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 0) { 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = dum->driver->setup (&dum->gadget, 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &setup); 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= 0) { 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no delays (max 64KB data stage) */ 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 64*1024; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto treat_control_like_bulk; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error, see below */ 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value < 0) { 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value != -EOPNOTSUPP) 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "setup --> %d\n", 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value); 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -EPIPE); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = 0; 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non-control requests */ 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = total; 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_ISOCHRONOUS: 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use urb->iso_frame_desc[i]. 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete whether or not ep has requests queued. 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * report random errors, to debug drivers. 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maybe_set_status (urb, -ENOSYS); 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this almost certainly polls too fast. 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = max (limit, periodic_bytes (dum, ep)); 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // case PIPE_BULK: case PIPE_CONTROL: 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds treat_control_like_bulk: 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = transfer (dum, urb, ep, limit); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* incomplete transfer? */ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status == -EINPROGRESS) 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb: 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->hcpriv = NULL; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del (&urbp->urbp_list); 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (urbp); 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = ep->setup_stage = 0; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL); 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* want a 1 msec delay here */ 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list_empty (&dum->urbp_list)) 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_dev (dum->udev); 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->udev = NULL; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \ 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((1 << USB_PORT_FEAT_C_CONNECTION) \ 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (1 << USB_PORT_FEAT_C_ENABLE) \ 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (1 << USB_PORT_FEAT_C_SUSPEND) \ 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (1 << USB_PORT_FEAT_C_RESET)) 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf) 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(dum->port_status & PORT_C_MASK)) 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = (1 << 1); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 1; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc) 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (desc, 0, sizeof *desc); 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescriptorType = 0x29; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescLength = 9; 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bNbrPorts = 1; 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bitmap [0] = 0xff; 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bitmap [1] = 0xff; 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control ( 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 typeReq, 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wValue, 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wIndex, 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wLength 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (typeReq) { 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearHubFeature: 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearPortFeature: 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20msec resume signaling */ 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 1; 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = jiffies + 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msecs_to_jiffies(20); 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status = 0; 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 0; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stop_activity(dum, dum->driver); 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(1 << wValue); 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubDescriptor: 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hub_descriptor ((struct usb_hub_descriptor *) buf); 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubStatus: 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u32 *) buf = __constant_cpu_to_le32 (0); 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetPortStatus: 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wIndex != 1) 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resets or resumes must GetPortStatus to 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete it!! 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->resuming && time_after (jiffies, dum->re_timeout)) { 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->resuming = 0; 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = 0; 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver && dum->driver->resume) { 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver->resume (&dum->gadget); 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && time_after (jiffies, dum->re_timeout)) { 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= (1 << USB_PORT_FEAT_C_RESET); 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(1 << USB_PORT_FEAT_RESET); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = 0; 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver) { 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= USB_PORT_STAT_ENABLE; 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* give it the best speed we agree on */ 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.speed = dum->driver->speed; 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0->maxpacket = 64; 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_HIGH_SPEED; 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.ep0->maxpacket = 8; 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_LOW_SPEED; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->gadget.speed = USB_SPEED_FULL; 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetHubFeature: 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetPortFeature: 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == 0) { 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1 << USB_PORT_FEAT_SUSPEND); 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver && dum->driver->suspend) { 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dum->lock); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver->suspend (&dum->gadget); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dum->lock); 15515742b0c95026c817d9c266174ca39a909e8d38caAlan Stern /* HNP would happen here; for now we 15525742b0c95026c817d9c266174ca39a909e8d38caAlan Stern * assume b_bus_req is always true. 15535742b0c95026c817d9c266174ca39a909e8d38caAlan Stern */ 15545742b0c95026c817d9c266174ca39a909e8d38caAlan Stern if (((1 << USB_DEVICE_B_HNP_ENABLE) 15555742b0c95026c817d9c266174ca39a909e8d38caAlan Stern & dum->devstatus) != 0) 15565742b0c95026c817d9c266174ca39a909e8d38caAlan Stern dev_dbg (dummy_dev(dum), 15575742b0c95026c817d9c266174ca39a909e8d38caAlan Stern "no HNP yet!\n"); 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_RESET: 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if it's already running, disconnect first */ 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->port_status & USB_PORT_STAT_ENABLE) { 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status &= ~(USB_PORT_STAT_ENABLE 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | USB_PORT_STAT_LOW_SPEED 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | USB_PORT_STAT_HIGH_SPEED); 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->driver) { 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "disconnect\n"); 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stop_activity (dum, dum->driver); 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME test that code path! */ 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50msec reset signaling */ 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->re_timeout = jiffies + msecs_to_jiffies(50); 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->port_status |= (1 << wValue); 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg (dummy_dev(dum), 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "hub control req%04x v%04x i%04x l%d\n", 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds typeReq, wValue, wIndex, wLength); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* "protocol stall" on error */ 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb) 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ep = usb_pipeendpoint (urb->pipe); 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return snprintf (buf, size, 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "urb/%p %s ep%d%s%s len %d/%d\n", 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb, 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->dev->speed) { 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: s = "ls"; break; 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: s = "fs"; break; 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: s = "hs"; break; 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: s = "?"; break; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s; }), 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; \ 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (usb_pipetype (urb->pipe)) { \ 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_CONTROL: s = ""; break; \ 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_BULK: s = "-bulk"; break; \ 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: s = "-int"; break; \ 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: s = "-iso"; break; \ 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s;}), 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length, urb->transfer_buffer_length); 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 162510523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf) 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd = dev_get_drvdata (dev); 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum = hcd_to_dummy (hcd); 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = 0; 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dum->lock, flags); 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t temp; 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += temp; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size += temp; 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dum->lock, flags); 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_start (struct usb_hcd *hcd) 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER side init ... we emulate a root hub that'll only ever 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * talk to one device (the slave side). Also appears in sysfs, 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just like more familiar pci-based HCDs. 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init (&dum->lock); 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer (&dum->timer); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->timer.function = dummy_timer; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->timer.data = (unsigned long) dum; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD (&dum->urbp_list); 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1666247f3105636caa9d1d8a4c3dfb755de42633bc80Alan Stern if ((retval = dummy_register_udc (dum)) != 0) 1667247f3105636caa9d1d8a4c3dfb755de42633bc80Alan Stern return retval; 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1669bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern /* only show a low-power port: just 8mA */ 1670bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern hcd->power_budget = 8; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd->state = HC_STATE_RUNNING; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16735742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG 16745742b0c95026c817d9c266174ca39a909e8d38caAlan Stern hcd->self.otg_port = 1; 16755742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif 16765742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file (dummy_dev(dum), &dev_attr_urbs); 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd) 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum = hcd_to_dummy (hcd); 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file (dummy_dev(dum), &dev_attr_urbs); 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver (dum->driver); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dummy_unregister_udc (dum); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info (dummy_dev(dum), "stopped\n"); 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd) 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dummy_g_get_frame (NULL); 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct hc_driver dummy_hcd = { 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = (char *) driver_name, 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .product_desc = "Dummy host controller", 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hcd_priv_size = sizeof(struct dummy), 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flags = HCD_USB2, 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = dummy_start, 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = dummy_stop, 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_enqueue = dummy_urb_enqueue, 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .urb_dequeue = dummy_urb_dequeue, 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame_number = dummy_h_get_frame, 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_status_data = dummy_hub_status, 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hub_control = dummy_hub_control, 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_probe (struct device *dev) 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id); 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!hcd) 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = hcd_to_dummy (hcd); 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_add_hcd(hcd, 0, 0); 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 0) { 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_hcd (hcd); 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = NULL; 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_remove (struct device *dev) 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd = dev_get_drvdata (dev); 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_remove_hcd (hcd); 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_put_hcd (hcd); 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_controller = NULL; 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_pdev_detect (void) 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = driver_register (&dummy_driver); 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_pdev.name = "hc"; 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_pdev.dev.driver = &dummy_driver; 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_pdev.dev.release = dummy_pdev_release; 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = platform_device_register (&the_pdev); 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister (&dummy_driver); 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_pdev_remove (void) 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds platform_device_unregister (&the_pdev); 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister (&dummy_driver); 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void) 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_disabled ()) 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = dummy_pdev_detect ()) != 0) 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((retval = dummy_probe (&the_pdev.dev)) != 0) 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dummy_pdev_remove (); 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init); 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void) 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dummy_remove (&the_pdev.dev); 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dummy_pdev_remove (); 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup); 1800