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 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver. USB traffic is simulated; there's 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware. Use this with two other drivers: 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Gadget driver, responding to requests (slave); 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Host-side device driver, as already familiar in Linux. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development, 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues. UML could help too. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 38d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 409454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h> 4127729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h> 4214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior#include <linux/scatterlist.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 4518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior#include <linux/io.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Host+Gadget Emulator" 50391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION "02 May 2005" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ 53caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern 5418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char driver_name[] = "dummy_hcd"; 5518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char driver_desc[] = "USB Host+Gadget Emulator"; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char gadget_name[] = "dummy_udc"; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_DESCRIPTION(DRIVER_DESC); 6018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_AUTHOR("David Brownell"); 6118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_LICENSE("GPL"); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters { 641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman bool is_super_speed; 657eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman bool is_high_speed; 661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}; 671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = { 697eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman .is_super_speed = false, 707eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman .is_high_speed = true, 711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}; 721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); 731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); 747eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); 757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep { 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_io; /* jiffies timestamp */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *desc; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep ep; 8518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior unsigned halted:1; 8618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior unsigned wedged:1; 8718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior unsigned already_seen:1; 8818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior unsigned setup_stage:1; 89a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned stream_en:1; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head queue; /* ep's requests */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request req; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return container_of(_ep, struct dummy_ep, ep); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_request *_req) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return container_of(_req, struct dummy_request, req); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints, 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types: 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * number can be changed. Names like "ep-a" are used for this type. 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Fixed Function: in other cases. some characteristics may be mutable; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that'd be hardware-specific. Names like "ep12out-bulk" are used. 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on. 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char ep0name[] = "ep0"; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char *const ep_name[] = { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0name, /* everyone has ep0 */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* act like a net2280: high speed, six configurable endpoints */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like pxa250: fifteen fixed function endpoints */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep15in-int", 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or like sa1100: two fixed function endpoints */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep1out-bulk", "ep2in-bulk", 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 14152950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 144d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE 64 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp { 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head urbp_list; 15014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior struct sg_mapping_iter miter; 15114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior u32 miter_started; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state { 156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RESET, 157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_SUSPENDED, 158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern DUMMY_RH_RUNNING 159391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}; 160391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd { 162cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum; 163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman enum dummy_rh_state rh_state; 164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct timer_list timer; 165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman u32 port_status; 166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman u32 old_status; 167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned long re_timeout; 168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct usb_device *udev; 170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct list_head urbp_list; 171a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior u32 stream_en_ep; 172a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior u8 num_stream[30 / 2]; 173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned active:1; 175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned old_active:1; 176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman unsigned resuming:1; 177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}; 178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE/GADGET side support 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior struct dummy_ep ep[DUMMY_ENDPOINTS]; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget gadget; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget_driver *driver; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request fifo_req; 19018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior u8 fifo_buf[FIFO_SIZE]; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 devstatus; 192391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned udc_suspended:1; 193f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned pullup:1; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER/HOST side support 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *hs_hcd; 1991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct dummy_hcd *ss_hcd; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 202cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return (struct dummy_hcd *) (hcd->hcd_priv); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of((void *) dum, struct usb_hcd, hcd_priv); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return dummy_hcd_to_hcd(dum)->self.controller; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct device *udc_dev(struct dummy *dum) 218d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 219d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return dum->gadget.dev.parent; 220d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 221d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 22218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy *ep_to_dummy(struct dummy_ep *ep) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return container_of(ep->gadget, struct dummy, gadget); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 227cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = container_of(gadget, struct dummy, gadget); 2301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed == USB_SPEED_SUPER) 2311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dum->ss_hcd; 2321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 2331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dum->hs_hcd; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy *gadget_dev_to_dummy(struct device *dev) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return container_of(dev, struct dummy, gadget.dev); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy the_controller; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */ 246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */ 24818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void nuke(struct dummy *dum, struct dummy_ep *ep) 249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 25018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior while (!list_empty(&ep->queue)) { 251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_request *req; 252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 25318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req = list_entry(ep->queue.next, struct dummy_request, queue); 25418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_del_init(&req->queue); 255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern req->req.status = -ESHUTDOWN; 256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 25718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 25818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req->req.complete(&ep->ep, &req->req); 25918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 26418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void stop_activity(struct dummy *dum) 265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy_ep *ep; 267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* prevent any more requests */ 269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->address = 0; 270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* The timer is left running so that outstanding URBs can fail */ 272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* nuke any pending requests first, so driver i/o is quiesced */ 27418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list) 27518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior nuke(dum, ep); 276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* driver now does any non-usb quiescing necessary */ 278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 2801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/** 2811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to 2821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * the hcd speed 2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for 2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * 2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the 2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd. 2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd) 2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct dummy *dum = dum_hcd->dum; 2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) { 2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) { 2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum->pullup || dum->udc_suspended) { 2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* UDC suspend must cause a disconnect */ 2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | 2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE); 2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) != 0) 3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* device is connected and not suspended */ 3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION | 3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SPEED_5GBPS) ; 3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) == 0) 3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE) == 1 && 3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dum_hcd->port_status & 3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_LS_U0) == 1 && 3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->active = 1; 3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) { 3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum->pullup || dum->udc_suspended) { 3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* UDC suspend must cause a disconnect */ 3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | 3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_ENABLE | 3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_LOW_SPEED | 3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_HIGH_SPEED | 3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SUSPEND); 3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) != 0) 3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; 3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->old_status & 3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION) == 0) 3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_PORT_STAT_C_CONNECTION << 16); 3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) 3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else if ((dum_hcd->port_status & 3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_SUSPEND) == 0 && 3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->active = 1; 3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 348f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */ 349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd) 350f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 351cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 352cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 353cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->active = 0; 3541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->pullup) 3551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 && 3561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->gadget.speed != USB_SPEED_SUPER) || 3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 && 3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->gadget.speed == USB_SPEED_SUPER)) 3591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return; 3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state_by_speed(dum_hcd); 362f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || 364cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->active) 365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 0; 366f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* if !connected or reset */ 368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || 369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { 3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 3711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * We're connected and not reset (reset occurred now), 3721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * and driver attached - disconnect! 3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && 3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && 3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver) { 3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman stop_activity(dum); 3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->disconnect(&dum->gadget); 3801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 381f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 382cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (dum_hcd->active != dum_hcd->old_active) { 383cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->old_active && dum->driver->suspend) { 3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->suspend(&dum->gadget); 3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else if (!dum_hcd->old_active && dum->driver->resume) { 3881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_unlock(&dum->lock); 3891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->driver->resume(&dum->gadget); 3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman spin_lock(&dum->lock); 391f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 392f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 393f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 394cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->old_status = dum_hcd->port_status; 395cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->old_active = dum_hcd->active; 396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 397f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 398f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/ 399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state. All the work is done when the host 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation. Real device controller 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc. 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dum->port_status & USB_PORT_STAT_ENABLE) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_enable(struct usb_ep *_ep, 41118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior const struct usb_endpoint_descriptor *desc) 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 414cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !desc || ep->desc || _ep->name == ep0name 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || desc->bDescriptorType != USB_DT_ENDPOINT) 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 42318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = ep_to_dummy(ep); 424cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum->driver) 425cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return -ESHUTDOWN; 426719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior 427719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!is_enabled(dum_hcd)) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman /* 432cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the 433cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * maximum packet size. 4341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * For SS devices the wMaxPacketSize is limited by 1024. 435cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman */ 43629cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto max = usb_endpoint_maxp(desc) & 0x7ff; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* drivers must not request bad settings, since lower levels 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (hardware or its drivers) may not check. some endpoints 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't do iso, many have maxpacket limitations, etc. 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since this "hardware" driver is here to help debugging, we 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have some extra sanity checks. (there could be more though, 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * especially for "ep9out" style fixed function ones.) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 44759f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior switch (usb_endpoint_type(desc)) { 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_BULK: 44918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (strstr(ep->ep.name, "-iso") 45018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior || strstr(ep->ep.name, "-int")) { 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 4551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (max == 1024) 4561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 4571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto done; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max == 512) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4619063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil goto done; 4629063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil case USB_SPEED_FULL: 4639063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil if (max == 8 || max == 16 || max == 32 || max == 64) 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we'll fake any legal size */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4669063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil /* save a return statement */ 4679063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil default: 4689063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil goto done; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_INT: 47218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 64) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 8) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_ENDPOINT_XFER_ISOC: 49218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (strstr(ep->ep.name, "-bulk") 49318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior || strstr(ep->ep.name, "-int")) 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware might not handle all packet sizes */ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 4971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1024) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max <= 1023) 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save a return statement */ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* few chips support control except on ep0 */ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->maxpacket = max; 516a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (usb_ss_max_streams(_ep->comp_desc)) { 517a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!usb_endpoint_xfer_bulk(desc)) { 518a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dev_err(udc_dev(dum), "Can't enable stream support on " 519a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior "non-bulk ep %s\n", _ep->name); 520a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return -EINVAL; 521a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 522a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ep->stream_en = 1; 523a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 5243cf0ad02e42a91e85ffe9bd67422dd266531d3ecSebastian Andrzej Siewior ep->desc = desc; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 526a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n", 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _ep->name, 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bEndpointAddress & 0x0f, 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *val; 53159f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior switch (usb_endpoint_type(desc)) { 5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_BULK: 5337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "bulk"; 5347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_ISOC: 5367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "iso"; 5377c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5387c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman case USB_ENDPOINT_XFER_INT: 5397c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "intr"; 5407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman default: 5427c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman val = "ctrl"; 5437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; val; }), 545a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max, ep->stream_en ? "enabled" : "disabled"); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* at this point real hardware should be NAKing transfers 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to that endpoint, until a buffer is queued to it. 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 550851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->halted = ep->wedged = 0; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_disable(struct usb_ep *_ep) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !ep->desc || _ep->name == ep0name) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 56618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = ep_to_dummy(ep); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock_irqsave(&dum->lock, flags); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->desc = NULL; 570a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ep->stream_en = 0; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 57218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior nuke(dum, ep); 57318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock_irqrestore(&dum->lock, flags); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic struct usb_request *dummy_alloc_request(struct usb_ep *_ep, 58018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior gfp_t mem_flags) 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 58718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5897039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn req = kzalloc(sizeof(*req), mem_flags); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 59218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior INIT_LIST_HEAD(&req->queue); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &req->req; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60120edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior if (!_ep || !_req) 60220edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior return; 60318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 60420edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior if (!ep->desc && _ep->name != ep0name) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req = usb_request_to_dummy_request(_req); 60818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior WARN_ON(!list_empty(&req->queue)); 60918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior kfree(req); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void fifo_complete(struct usb_ep *ep, struct usb_request *req) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_queue(struct usb_ep *_ep, struct usb_request *_req, 61755016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags) 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 622cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req = usb_request_to_dummy_request(_req); 62618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (!_req || !list_empty(&req->queue) || !_req->complete) 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || (!ep->desc && _ep->name != ep0name)) 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = ep_to_dummy(ep); 634719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 635cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum->driver || !is_enabled(dum_hcd)) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 63918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep, _req, _ep->name, _req->length, _req->buf); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -EINPROGRESS; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = 0; 64418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock_irqsave(&dum->lock, flags); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* implement an emulated single-request FIFO */ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 64818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_empty(&dum->fifo_req.queue) && 64918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_empty(&ep->queue) && 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->length <= FIFO_SIZE) { 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = &dum->fifo_req; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req = *_req; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.buf = dum->fifo_buf; 65418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior memcpy(dum->fifo_buf, _req->buf, _req->length); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.context = dum; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.complete = fifo_complete; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 658c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell list_add_tail(&req->queue, &ep->queue); 65918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->actual = _req->length; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = 0; 66218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior _req->complete(_ep, _req); 66318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 664c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell } else 665c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell list_add_tail(&req->queue, &ep->queue); 66618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock_irqrestore(&dum->lock, flags); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* real hardware would likely enable transfers here, in case 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it'd been left NAKing. 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = -EINVAL; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req = NULL; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep || !_req) 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 68418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 68518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = ep_to_dummy(ep); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior local_irq_save(flags); 69118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 69218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_for_each_entry(req, &ep->queue, queue) { 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (&req->req == _req) { 69418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_del_init(&req->queue); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _req->status = -ECONNRESET; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 70018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 70318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "dequeued req %p from %s, len %d buf %p\n", 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req, _ep->name, _req->length, _req->buf); 70618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior _req->complete(_ep, _req); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 70818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior local_irq_restore(flags); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 713851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!_ep) 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 72018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep = usb_ep_to_dummy_ep(_ep); 72118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = ep_to_dummy(ep); 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver) 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ESHUTDOWN; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!value) 725851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->halted = ep->wedged = 0; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && 72718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior !list_empty(&ep->queue)) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 729851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern else { 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 1; 731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern if (wedged) 732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern ep->wedged = 1; 733851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME clear emulated data toggle too */ 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int 739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value) 740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{ 741851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return dummy_set_halt_and_wedge(_ep, value, 0); 742851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern} 743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern 744851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep) 745851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{ 746851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern if (!_ep || _ep->name == ep0name) 747851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return -EINVAL; 748851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern return dummy_set_halt_and_wedge(_ep, 1, 1); 749851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern} 750851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = { 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable = dummy_enable, 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disable = dummy_disable, 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .alloc_request = dummy_alloc_request, 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .free_request = dummy_free_request, 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queue = dummy_queue, 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = dummy_dequeue, 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_halt = dummy_set_halt, 762851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern .set_wedge = dummy_set_wedge, 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */ 76818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_g_get_frame(struct usb_gadget *_gadget) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timeval tv; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior do_gettimeofday(&tv); 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tv.tv_usec / 1000; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_wakeup(struct usb_gadget *_gadget) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 778cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 780cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = gadget_to_dummy_hcd(_gadget); 781cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE) 7825742b0c95026c817d9c266174ca39a909e8d38caAlan Stern | (1 << USB_DEVICE_REMOTE_WAKEUP)))) 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 784cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0) 785391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ENOLINK; 786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && 787cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state != DUMMY_RH_SUSPENDED) 788391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -EIO; 789391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 790391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* FIXME: What if the root hub is suspended but the port isn't? */ 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* hub notices our request, issues downstream resume, etc */ 793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 1; 794cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); 795cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_set_selfpowered(struct usb_gadget *_gadget, int value) 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = gadget_to_dummy_hcd(_gadget)->dum; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value) 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewiorstatic void dummy_udc_update_ep0(struct dummy *dum) 812b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{ 813c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior if (dum->gadget.speed == USB_SPEED_SUPER) 814b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dum->ep[0].ep.maxpacket = 9; 815c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior else 816b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dum->ep[0].ep.maxpacket = 64; 817b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior} 818b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior 81918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_pullup(struct usb_gadget *_gadget, int value) 820f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{ 821d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior struct dummy_hcd *dum_hcd; 822f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern struct dummy *dum; 823f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern unsigned long flags; 824f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 825b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dum = gadget_dev_to_dummy(&_gadget->dev); 826b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior 827b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior if (value && dum->driver) { 828b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior if (mod_data.is_super_speed) 8297177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz dum->gadget.speed = dum->driver->max_speed; 830b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior else if (mod_data.is_high_speed) 831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, 8327177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz dum->driver->max_speed); 833b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior else 834b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dum->gadget.speed = USB_SPEED_FULL; 835d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewior dummy_udc_update_ep0(dum); 836b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior 8377177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz if (dum->gadget.speed < dum->driver->max_speed) 838b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "This device can perform faster" 8397177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz " if you connect it to a %s port...\n", 8407177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz usb_speed_string(dum->driver->max_speed)); 841b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior } 842d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior dum_hcd = gadget_to_dummy_hcd(_gadget); 843d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior 84418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock_irqsave(&dum->lock, flags); 845f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern dum->pullup = (value != 0); 846d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior set_link_state(dum_hcd); 84718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock_irqrestore(&dum->lock, flags); 848b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior 849d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 850f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern return 0; 851f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern} 852f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 853aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g, 854aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct usb_gadget_driver *driver); 855aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g, 856aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct usb_gadget_driver *driver); 8570f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = { 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_frame = dummy_g_get_frame, 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wakeup = dummy_wakeup, 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_selfpowered = dummy_set_selfpowered, 862f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern .pullup = dummy_pullup, 863aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior .udc_start = dummy_udc_start, 864aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior .udc_stop = dummy_udc_stop, 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */ 87018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic ssize_t show_function(struct device *dev, struct device_attribute *attr, 87118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior char *buf) 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 87318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior struct dummy *dum = gadget_dev_to_dummy(dev); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dum->driver || !dum->driver->function) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 87718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 87918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic DEVICE_ATTR(function, S_IRUGO, show_function, NULL); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration. 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work. So most implementations of these api calls will rely on the 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware. But curious 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption. 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers: just add to a big root hub. 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 897aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g, 898aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct usb_gadget_driver *driver) 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 900aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); 901aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct dummy *dum = dum_hcd->dum; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9037177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz if (driver->max_speed == USB_SPEED_UNKNOWN) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SLAVE side init ... the layer above hardware, which 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't enumerate without help from the driver we're binding. 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9105742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->devstatus = 0; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = driver; 91418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n", 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 919aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g, 920aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct usb_gadget_driver *driver) 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 922aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); 923aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior struct dummy *dum = dum_hcd->dum; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver->driver.name); 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dum->driver = NULL; 9292542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be 936d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */ 93718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_gadget_release(struct device *dev) 938d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 939cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return; 940d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 941d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9420fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum) 9430fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{ 9440fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior int i; 9450fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9460fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&dum->gadget.ep_list); 9470fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior for (i = 0; i < DUMMY_ENDPOINTS; i++) { 9480fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior struct dummy_ep *ep = &dum->ep[i]; 9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9500fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior if (!ep_name[i]) 9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior break; 9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.name = ep_name[i]; 9530fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.ops = &dummy_ep_ops; 9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); 9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->halted = ep->wedged = ep->already_seen = 9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->setup_stage = 0; 9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->ep.maxpacket = ~0; 958c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior ep->ep.max_streams = 16; 9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->last_io = jiffies; 9600fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->gadget = &dum->gadget; 9610fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior ep->desc = NULL; 9620fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&ep->queue); 9630fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior } 9640fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9650fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior dum->gadget.ep0 = &dum->ep[0].ep; 9660fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior list_del_init(&dum->ep[0].ep.ep_list); 9670fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior INIT_LIST_HEAD(&dum->fifo_req.queue); 968f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior 969f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG 970f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior dum->gadget.is_otg = 1; 971f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif 9720fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior} 9730fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 97418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_udc_probe(struct platform_device *pdev) 975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = &the_controller; 977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern int rc; 978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 979d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.name = gadget_name; 980d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.ops = &dummy_ops; 981d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz dum->gadget.max_speed = USB_SPEED_SUPER; 982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9830031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers dev_set_name(&dum->gadget.dev, "gadget"); 9848364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dum->gadget.dev.parent = &pdev->dev; 985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern dum->gadget.dev.release = dummy_gadget_release; 98618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior rc = device_register(&dum->gadget.dev); 98775d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar if (rc < 0) { 98875d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar put_device(&dum->gadget.dev); 989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 99075d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar } 991d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 9920fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior init_dummy_udc_hw(dum); 9930fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior 9940f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); 9950f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior if (rc < 0) 9960f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior goto err_udc; 9970f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 99818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior rc = device_create_file(&dum->gadget.dev, &dev_attr_function); 999efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern if (rc < 0) 10000f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior goto err_dev; 10010f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior platform_set_drvdata(pdev, dum); 10020f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior return rc; 10030f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 10040f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev: 10050f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&dum->gadget); 10060f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc: 10070f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior device_unregister(&dum->gadget.dev); 1008d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return rc; 1009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 101118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_udc_remove(struct platform_device *pdev) 1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{ 101318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior struct dummy *dum = platform_get_drvdata(pdev); 1014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10150f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&dum->gadget); 101618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior platform_set_drvdata(pdev, NULL); 101718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior device_remove_file(&dum->gadget.dev, &dev_attr_function); 101818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior device_unregister(&dum->gadget.dev); 1019d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 1020d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern} 1021d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 1022fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd, 1023fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior int suspend) 1024391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1025fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior spin_lock_irq(&dum->lock); 1026fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dum->udc_suspended = suspend; 1027d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior set_link_state(dum_hcd); 1028fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior spin_unlock_irq(&dum->lock); 1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior} 1030fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior 1031fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state) 1032fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{ 1033fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy *dum = platform_get_drvdata(pdev); 1034fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1036fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dummy_udc_pm(dum, dum_hcd, 1); 1038d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 1039391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1040391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1042fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev) 1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 1044fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy *dum = platform_get_drvdata(pdev); 1045fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); 1046391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1047fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 1048fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior dummy_udc_pm(dum, dum_hcd, 0); 1049d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); 1050391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 1051391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 1052391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 10533ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = { 1054d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_udc_probe, 1055d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_udc_remove, 1056391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_udc_suspend, 1057391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_udc_resume, 10583ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 10593ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) gadget_name, 10603ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 10613ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 1062d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 1063d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1066a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc) 1067a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{ 1068a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int index; 1069a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1070a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = usb_endpoint_num(desc) << 1; 1071a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (usb_endpoint_dir_in(desc)) 1072a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index |= 1; 1073a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return index; 1074a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior} 1075a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers. 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller. 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback. that callback connects writes from 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules. 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1088a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb) 1089a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{ 1090a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior const struct usb_endpoint_descriptor *desc = &urb->ep->desc; 1091a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior u32 index; 1092a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1093a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!usb_endpoint_xfer_bulk(desc)) 1094a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return 0; 1095a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1096a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = dummy_get_ep_idx(desc); 1097a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return (1 << index) & dum_hcd->stream_en_ep; 1098a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior} 1099a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1100a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior/* 1101a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * The max stream number is saved as a nibble so for the 30 possible endpoints 1102a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0 1103a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * means we use only 1 stream). The maximum according to the spec is 16bit so 1104a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * if the 16 stream limit is about to go, the array size should be incremented 1105a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * to 30 elements of type u16. 1106a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior */ 1107a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd, 1108a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int pipe) 1109a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{ 1110a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int max_streams; 1111a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1112a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; 1113a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (usb_pipeout(pipe)) 1114a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams >>= 4; 1115a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior else 1116a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams &= 0xf; 1117a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams++; 1118a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return max_streams; 1119a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior} 1120a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1121a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd, 1122a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int pipe, unsigned int streams) 1123a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{ 1124a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int max_streams; 1125a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1126a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior streams--; 1127a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; 1128a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (usb_pipeout(pipe)) { 1129a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior streams <<= 4; 1130a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams &= 0xf; 1131a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } else { 1132a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams &= 0xf0; 1133a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 1134a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams |= streams; 1135a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams; 1136a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior} 1137a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1138a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb) 1139a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{ 1140a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int max_streams; 1141a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int enabled; 1142a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1143a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior enabled = dummy_ep_stream_en(dum_hcd, urb); 1144a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!urb->stream_id) { 1145a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (enabled) 1146a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return -EINVAL; 1147a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return 0; 1148a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 1149a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!enabled) 1150a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return -EINVAL; 1151a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1152a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_streams = get_max_streams_for_pipe(dum_hcd, 1153a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior usb_pipeendpoint(urb->pipe)); 1154a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (urb->stream_id > max_streams) { 1155a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n", 1156a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior urb->stream_id); 1157a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior BUG(); 1158a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return -EINVAL; 1159a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 1160a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return 0; 1161a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior} 1162a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 116318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_urb_enqueue( 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb, 116655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 1168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1171e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior urbp = kmalloc(sizeof *urbp, mem_flags); 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urbp) 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urbp->urb = urb; 117714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior urbp->miter_started = 0; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1181a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1182a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior rc = dummy_validate_stream(dum_hcd, urb); 1183a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (rc) { 1184a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior kfree(urbp); 1185a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior goto done; 1186a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 1187a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 1188e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_link_urb_to_ep(hcd, urb); 1189e9df41c5c5899259541dc928872cad4d07b82076Alan Stern if (rc) { 1190e9df41c5c5899259541dc928872cad4d07b82076Alan Stern kfree(urbp); 1191e9df41c5c5899259541dc928872cad4d07b82076Alan Stern goto done; 1192e9df41c5c5899259541dc928872cad4d07b82076Alan Stern } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1194cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum_hcd->udev) { 1195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->udev = urb->dev; 1196cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_get_dev(dum_hcd->udev); 1197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (unlikely(dum_hcd->udev != urb->dev)) 1198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n"); 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list); 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->hcpriv = urbp; 120218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (usb_pipetype(urb->pipe) == PIPE_CONTROL) 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 1; /* mark as a new urb */ 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kick the scheduler, it'll do the rest */ 1206cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!timer_pending(&dum_hcd->timer)) 1207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies + 1); 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1209e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done: 1210cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 1211e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1214e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1216cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 1217391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern unsigned long flags; 1218e9df41c5c5899259541dc928872cad4d07b82076Alan Stern int rc; 1219391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1220391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* giveback happens automatically in timer callback, 1221391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern * so make sure the callback happens */ 1222cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1224e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1225e9df41c5c5899259541dc928872cad4d07b82076Alan Stern rc = usb_hcd_check_unlink_urb(hcd, urb, status); 1226cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && 1227cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman !list_empty(&dum_hcd->urbp_list)) 1228cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies); 1229e9df41c5c5899259541dc928872cad4d07b82076Alan Stern 1230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 1231e9df41c5c5899259541dc928872cad4d07b82076Alan Stern return rc; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1234a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewiorstatic int dummy_perform_transfer(struct urb *urb, struct dummy_request *req, 1235a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior u32 len) 1236a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior{ 1237a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior void *ubuf, *rbuf; 123814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior struct urbp *urbp = urb->hcpriv; 1239a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior int to_host; 124014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior struct sg_mapping_iter *miter = &urbp->miter; 124114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior u32 trans = 0; 124214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior u32 this_sg; 124314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior bool next_sg; 1244a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior 1245a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior to_host = usb_pipein(urb->pipe); 1246a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior rbuf = req->req.buf + req->req.actual; 1247a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior 124814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (!urb->num_sgs) { 124914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior ubuf = urb->transfer_buffer + urb->actual_length; 125014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (to_host) 125114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior memcpy(ubuf, rbuf, len); 125214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior else 125314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior memcpy(rbuf, ubuf, len); 125414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior return len; 125514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } 125614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 125714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (!urbp->miter_started) { 125814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior u32 flags = SG_MITER_ATOMIC; 125914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 126014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (to_host) 126114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior flags |= SG_MITER_TO_SG; 126214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior else 126314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior flags |= SG_MITER_FROM_SG; 126414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 126514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior sg_miter_start(miter, urb->sg, urb->num_sgs, flags); 126614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior urbp->miter_started = 1; 126714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } 126814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior next_sg = sg_miter_next(miter); 126914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (next_sg == false) { 127014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior WARN_ON_ONCE(1); 127114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior return -EINVAL; 127214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } 127314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior do { 127414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior ubuf = miter->addr; 127514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior this_sg = min_t(u32, len, miter->length); 127614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior miter->consumed = this_sg; 127714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior trans += this_sg; 127814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 127914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (to_host) 128014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior memcpy(ubuf, rbuf, this_sg); 128114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior else 128214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior memcpy(rbuf, ubuf, this_sg); 128314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior len -= this_sg; 128414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 128514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (!len) 128614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior break; 128714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior next_sg = sg_miter_next(miter); 128814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior if (next_sg == false) { 128914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior WARN_ON_ONCE(1); 129014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior return -EINVAL; 129114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } 129214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 129314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior rbuf += this_sg; 129414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } while (1); 129514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior 129614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior sg_miter_stop(miter); 129714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior return trans; 1298a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior} 1299a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */ 1301a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, 1302a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior struct dummy_ep *ep, int limit, int *status) 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1304a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior struct dummy *dum = dum_hcd->dum; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop: 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if there's no request queued, the device is NAKing; return */ 130918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_for_each_entry(req, &ep->queue, queue) { 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned host_len, dev_len, len; 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int is_short, to_host; 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rescan = 0; 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1314a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (dummy_ep_stream_en(dum_hcd, urb)) { 1315a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if ((urb->stream_id != req->req.stream_id)) 1316a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior continue; 1317a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 1318a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1..N packets of ep->ep.maxpacket each ... the last one 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be short (including zero length). 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * writer can send a zlp explicitly (length 0) or implicitly 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (length mod maxpacket zero, and 'zero' flag); they always 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * terminate reads. 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_len = urb->transfer_buffer_length - urb->actual_length; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_len = req->req.length - req->req.actual; 132818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior len = min(host_len, dev_len); 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME update emulated data toggle too */ 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior to_host = usb_pipein(urb->pipe); 133318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (unlikely(len == 0)) 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = 1; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not enough bandwidth left? */ 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (limit < ep->ep.maxpacket && limit < len) 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 133918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior len = min_t(unsigned, len, limit); 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len == 0) 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use an extra pass for the final short packet */ 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > ep->ep.maxpacket) { 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= (len % ep->ep.maxpacket); 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_short = (len % ep->ep.maxpacket) != 0; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1350a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior len = dummy_perform_transfer(urb, req, len); 1351a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 1353b1443ac0e486842c133b8805ee035ab3ff918763Dan Carpenter if ((int)len < 0) { 135414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior req->req.status = len; 135514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } else { 135614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior limit -= len; 135714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior urb->actual_length += len; 135814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior req->req.actual += len; 135914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior } 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* short packets terminate, maybe with overflow/underflow. 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's only really an error to write too much. 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partially filling a buffer optionally blocks queue advances 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (so completion handlers can clean up the queue) but we don't 1367b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern * need to emulate such data-in-flight. 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_short) { 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len == dev_len) { 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 13724d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (to_host) { 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev_len > host_len) 13764d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = -EOVERFLOW; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13784d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!to_host) { 13804d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_len > dev_len) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* many requests terminate without a short packet */ 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.length == req->req.actual 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !req->req.zero) 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = 0; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->transfer_buffer_length == urb->actual_length 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !(urb->transfer_flags 13944d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern & URB_ZERO_PACKET)) 13954d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern *status = 0; 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device side completion --> continuable */ 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->req.status != -EINPROGRESS) { 140018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_del_init(&req->queue); 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 140318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req->req.complete(&ep->ep, &req->req); 140418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* requests might have been unlinked... */ 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rescan = 1; 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* host side completion --> terminate */ 14114d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (*status != -EINPROGRESS) 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* rescan to continue with any other queued i/o */ 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rescan) 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto top; 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int periodic_bytes(struct dummy *dum, struct dummy_ep *ep) 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit = ep->ep.maxpacket; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dum->gadget.speed == USB_SPEED_HIGH) { 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* high bandwidth mode */ 142929cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto tmp = usb_endpoint_maxp(ep->desc); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (tmp >> 11) & 0x03; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp *= 8 /* applies to entire frame */; 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit += limit * tmp; 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->gadget.speed == USB_SPEED_SUPER) { 143559f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior switch (usb_endpoint_type(ep->desc)) { 14361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_ISOC: 14371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Sec. 4.4.8.2 USB3.0 Spec */ 14381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman limit = 3 * 16 * 1024 * 8; 14391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_INT: 14411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Sec. 4.4.7.2 USB3.0 Spec */ 14421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman limit = 3 * 1024 * 8; 14431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_ENDPOINT_XFER_BULK: 14451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman default: 14461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return limit; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1452cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd) ((dum_hcd->port_status & \ 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_PORT_STAT_SUSPEND)) \ 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic struct dummy_ep *find_endpoint(struct dummy *dum, u8 address) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? 14621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum->ss_hcd : dum->hs_hcd))) 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((address & ~USB_DIR_IN) == 0) 146518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return &dum->ep[0]; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < DUMMY_ENDPOINTS; i++) { 146718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior struct dummy_ep *ep = &dum->ep[i]; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep->desc) 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->desc->bEndpointAddress == address) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ep; 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest (Dev_Request | USB_DIR_IN) 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest (Intf_Request | USB_DIR_IN) 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest (Ep_Request | USB_DIR_IN) 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/** 14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers 14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller) 14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle 14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control 14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * request 14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status 14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * 14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled 14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * 1 - if the request wasn't handles 14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * error code on error 14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */ 1499cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, 15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman struct usb_ctrlrequest *setup, 15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman int *status) 15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{ 15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman struct dummy_ep *ep2; 1504cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman int ret_val = 1; 15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman unsigned w_index; 15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman unsigned w_value; 15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_index = le16_to_cpu(setup->wIndex); 15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value = le16_to_cpu(setup->wValue); 15118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (setup->bRequest) { 15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_SET_ADDRESS: 15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType != Dev_Request) 15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->address = w_value; 15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dev_dbg(udc_dev(dum), "set_address = %d\n", 15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value); 15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_SET_FEATURE: 15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_Request) { 15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (w_value) { 15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_REMOTE_WAKEUP: 15268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_B_HNP_ENABLE: 15288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.b_hnp_enable = 1; 15298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_A_HNP_SUPPORT: 15318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.a_hnp_support = 1; 15328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_A_ALT_HNP_SUPPORT: 15348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->gadget.a_alt_hnp_support = 1; 15358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U1_ENABLE: 15371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 15391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U1_ENABLED; 15401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 15411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 15421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U2_ENABLE: 15441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 15461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U2_ENABLED; 15471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 15481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 15491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_LTM_ENABLE: 15511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 15531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_LTM_ENABLED; 15541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 15551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 15561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman default: 15588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 15598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (ret_val == 0) { 15618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->devstatus |= (1 << w_value); 15628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 15638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == Ep_Request) { 15658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* endpoint halt */ 15668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 15678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2 || ep2->ep.name == ep0name) { 15688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 15698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2->halted = 1; 15728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 15738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 15748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 15758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_CLEAR_FEATURE: 15778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_Request) { 15788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 15798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman switch (w_value) { 15808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_DEVICE_REMOTE_WAKEUP: 15818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman w_value = USB_DEVICE_REMOTE_WAKEUP; 15828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 15831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U1_ENABLE: 15841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 15861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U1_ENABLED; 15871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 15881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 15891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_U2_ENABLE: 15911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 15931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_U2_ENABLED; 15941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 15951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 15961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 15971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_DEVICE_LTM_ENABLE: 15981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dummy_hcd_to_hcd(dum_hcd)->speed == 15991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman HCD_USB3) 16001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman w_value = USB_DEV_STAT_LTM_ENABLED; 16011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 16021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ret_val = -EOPNOTSUPP; 16031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 16048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman default: 16058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 16068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 16078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (ret_val == 0) { 16098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman dum->devstatus &= ~(1 << w_value); 16108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 16118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == Ep_Request) { 16138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* endpoint halt */ 16148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 16158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2) { 16168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 16178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 16188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2->wedged) 16208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2->halted = 0; 16218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 16228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 16238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 16258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman case USB_REQ_GET_STATUS: 16268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Dev_InRequest 16278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman || setup->bRequestType == Intf_InRequest 16288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman || setup->bRequestType == Ep_InRequest) { 16298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman char *buf; 16308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman /* 16318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * device: remote wakeup, selfpowered 16328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * interface: nothing 16338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * endpoint: halt 16348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */ 16358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf = (char *)urb->transfer_buffer; 16368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (urb->transfer_buffer_length > 0) { 16378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (setup->bRequestType == Ep_InRequest) { 16388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ep2 = find_endpoint(dum, w_index); 16398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (!ep2) { 16408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = -EOPNOTSUPP; 16418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 16428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = ep2->halted; 16448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else if (setup->bRequestType == 16458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman Dev_InRequest) { 16468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = (u8)dum->devstatus; 16478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } else 16488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[0] = 0; 16498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman if (urb->transfer_buffer_length > 1) 16518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman buf[1] = 0; 16528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman urb->actual_length = min_t(u32, 2, 16538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman urb->transfer_buffer_length); 16548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman ret_val = 0; 16558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *status = 0; 16568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman break; 16588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman } 16598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman return ret_val; 16608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman} 16618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq(). 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1665cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd) 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1667cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd; 1668cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum = dum_hcd->dum; 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp, *tmp; 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit, total; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* simplistic model for one frame's bandwidth */ 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dum->gadget.speed) { 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 8/*bytes*/ * 12/*packets*/; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 64/*bytes*/ * 19/*packets*/; 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_SUPER: 16861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Bus speed is 500000 bytes/ms, so use a little less */ 16871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman total = 490000; 16881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1690cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME if HZ != 1000 this will probably misbehave ... */ 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look at each urb queued by the host side driver */ 169718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock_irqsave(&dum->lock, flags); 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1699cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!dum_hcd->udev) { 1700cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_err(dummy_dev(dum_hcd), 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "timer fired with no URBs pending?\n"); 170218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock_irqrestore(&dum->lock, flags); 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < DUMMY_ENDPOINTS; i++) { 170718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (!ep_name[i]) 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 170918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum->ep[i].already_seen = 0; 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart: 1713cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) { 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_request *req; 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 address; 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy_ep *ep = NULL; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 17194d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern int status = -EINPROGRESS; 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = urbp->urb; 1722eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern if (urb->unlinked) 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 1724cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) 1725391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern continue; 172618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior type = usb_pipetype(urb->pipe); 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* used up this frame's non-periodic bandwidth? 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME there's infinite bandwidth for control and 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * periodic transfers ... unrealistic. 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total <= 0 && type == PIPE_BULK) 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the gadget's ep for this request (if configured) */ 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address = usb_pipeendpoint (urb->pipe); 173718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (usb_pipein(urb->pipe)) 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address |= USB_DIR_IN; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = find_endpoint(dum, address); 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) { 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set_configuration() disagreement */ 1742cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no ep configured for urb %p\n", 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb); 17454d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPROTO; 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->already_seen) 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 1; 175218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (ep == &dum->ep[0] && urb->error_count) { 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 1; /* a new urb */ 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->error_count = 0; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep->halted && !ep->setup_stage) { 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE: must not be iso! */ 1758cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n", 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->ep.name, urb); 17604d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME make sure both ends agree on maxpacket */ 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* handle control requests */ 176618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (ep == &dum->ep[0] && ep->setup_stage) { 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ctrlrequest setup; 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = 1; 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 177018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior setup = *(struct usb_ctrlrequest *) urb->setup_packet; 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* paranoia, in case of stale queued data */ 177218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_for_each_entry(req, &ep->queue, queue) { 177318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_del_init(&req->queue); 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->req.status = -EOVERFLOW; 177518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), "stale req = %p\n", 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req); 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 177818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 177918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior req->req.complete(&ep->ep, &req->req); 178018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = 0; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver never sees set_address or operations 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on standard feature flags. some hardware doesn't 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even expose them. 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->setup_stage = 0; 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->halted = 0; 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman value = handle_control_request(dum_hcd, urb, &setup, 17948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman &status); 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* gadget driver handles all other requests. block 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until setup() returns; no reentrancy issues etc. 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 0) { 180018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 180118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior value = dum->driver->setup(&dum->gadget, 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &setup); 180318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= 0) { 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no delays (max 64KB data stage) */ 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 64*1024; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto treat_control_like_bulk; 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error, see below */ 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value < 0) { 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value != -EOPNOTSUPP) 181518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(udc_dev(dum), 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "setup --> %d\n", 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value); 18184d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -EPIPE; 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length = 0; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto return_urb; 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non-control requests */ 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = total; 182718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior switch (usb_pipetype(urb->pipe)) { 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_ISOCHRONOUS: 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use urb->iso_frame_desc[i]. 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete whether or not ep has requests queued. 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * report random errors, to debug drivers. 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 183418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior limit = max(limit, periodic_bytes(dum, ep)); 18354d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern status = -ENOSYS; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIPE_INTERRUPT: 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME is it urb->interval since the last xfer? 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this almost certainly polls too fast. 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 184218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior limit = max(limit, periodic_bytes(dum, ep)); 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 184618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiortreat_control_like_bulk: 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->last_io = jiffies; 1848a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior total = transfer(dum_hcd, urb, ep, limit, &status); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* incomplete transfer? */ 18534d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern if (status == -EINPROGRESS) 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb: 185718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior list_del(&urbp->urbp_list); 185818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior kfree(urbp); 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep) 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->already_seen = ep->setup_stage = 0; 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1862cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb); 186318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock(&dum->lock); 1864cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status); 186518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_lock(&dum->lock); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart; 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1870cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (list_empty(&dum_hcd->urbp_list)) { 1871cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_dev(dum_hcd->udev); 1872cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->udev = NULL; 1873cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { 1874391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern /* want a 1 msec delay here */ 1875cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1)); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 187818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior spin_unlock_irqrestore(&dum->lock, flags); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \ 1884c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern ((USB_PORT_STAT_C_CONNECTION \ 1885c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_ENABLE \ 1886c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_SUSPEND \ 1887c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_OVERCURRENT \ 1888c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern | USB_PORT_STAT_C_RESET) << 16) 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 189018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hub_status(struct usb_hcd *hcd, char *buf) 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1892cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1894391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern int retval = 0; 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1896cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1898cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1899541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) 1900391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern goto done; 1901f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1902cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) { 1903cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1904cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 1905cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 1906f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern } 1907f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 1908cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & PORT_C_MASK) != 0) { 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = (1 << 1); 1910cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n", 1911cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status); 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 1; 1913cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED) 191418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior usb_hcd_resume_root_hub(hcd); 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1916391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone: 1917cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 19221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc) 19231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 19241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman memset(desc, 0, sizeof *desc); 19251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bDescriptorType = 0x2a; 19261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bDescLength = 12; 19271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->wHubCharacteristics = cpu_to_le16(0x0001); 19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->bNbrPorts = 1; 19291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ 19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman desc->u.ss.DeviceRemovable = 0xffff; 19311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 193318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline void hub_descriptor(struct usb_hub_descriptor *desc) 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 193518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior memset(desc, 0, sizeof *desc); 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescriptorType = 0x29; 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescLength = 9; 1938fd05e720099e8eeddb378305d1a41c1445344b91Al Viro desc->wHubCharacteristics = cpu_to_le16(0x0001); 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bNbrPorts = 1; 1940dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[0] = 0xff; 1941dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn desc->u.hs.DeviceRemovable[1] = 0xff; 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hub_control( 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 typeReq, 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wValue, 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wIndex, 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wLength 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 1952cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1956541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) 1957391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return -ETIMEDOUT; 1958391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 1959cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 1960cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 1961cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (typeReq) { 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearHubFeature: 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearPortFeature: 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 19681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 19691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_SUSPEND req not " 19711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 3.0 roothub\n"); 19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 1974cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) { 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20msec resume signaling */ 1976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->resuming = 1; 1977cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + 1978f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern msecs_to_jiffies(20); 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum_hcd->port_status & USB_PORT_STAT_POWER) 19841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "power-off\n"); 19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 19871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum_hcd->port_status & 19881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_STAT_POWER) 19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "power-off\n"); 1991f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1993cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~(1 << wValue); 1994cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubDescriptor: 19981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3 && 19991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (wLength < USB_DT_SS_HUB_SIZE || 20001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman wValue != (USB_DT_SS_HUB << 8))) { 20011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "Wrong hub descriptor type for " 20031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB 3.0 roothub.\n"); 20041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) 20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ss_hub_descriptor((struct usb_hub_descriptor *) buf); 20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hub_descriptor((struct usb_hub_descriptor *) buf); 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubStatus: 201218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior *(__le32 *) buf = cpu_to_le32(0); 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetPortStatus: 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wIndex != 1) 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resets or resumes must GetPortStatus to 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete it!! 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2021cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->resuming && 2022cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman time_after_eq(jiffies, dum_hcd->re_timeout)) { 2023cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 2024cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2026cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 && 2027cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman time_after_eq(jiffies, dum_hcd->re_timeout)) { 2028cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16); 2029cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status &= ~USB_PORT_STAT_RESET; 2030cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->dum->pullup) { 2031cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_ENABLE; 20321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 20331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed < HCD_USB3) { 20341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman switch (dum_hcd->dum->gadget.speed) { 20351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_HIGH: 20361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 20371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_HIGH_SPEED; 20381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_SPEED_LOW: 20401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->dum->gadget.ep0-> 20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman maxpacket = 8; 20421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= 20431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_LOW_SPEED; 20441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman default: 20461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->dum->gadget.speed = 20471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SPEED_FULL; 20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2053cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 205418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ((__le16 *) buf)[0] = cpu_to_le16(dum_hcd->port_status); 205518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ((__le16 *) buf)[1] = cpu_to_le16(dum_hcd->port_status >> 16); 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetHubFeature: 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetPortFeature: 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 20621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_LINK_STATE: 20631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 20641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_LINK_STATE req not " 20661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 20671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 20701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * Since this is dummy we don't have an actual link so 20711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * there is nothing to do for the SET_LINK_STATE cmd 20721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 20731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_U1_TIMEOUT: 20751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_U2_TIMEOUT: 20761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* TODO: add suspend/resume support! */ 20771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 20781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_U1/2_TIMEOUT req not " 20801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 20811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 20831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 20851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Applicable only for USB2.0 hub */ 20861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 20871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 20881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_SUSPEND req not " 20891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 3.0 roothub\n"); 20901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 20911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 2092cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->active) { 2093cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_SUSPEND; 2094f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern 2095f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* HNP would happen here; for now we 2096f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern * assume b_bus_req is always true. 2097f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern */ 2098cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 2099f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern if (((1 << USB_DEVICE_B_HNP_ENABLE) 2100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman & dum_hcd->dum->devstatus) != 0) 2101cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 21025742b0c95026c817d9c266174ca39a909e8d38caAlan Stern "no HNP yet!\n"); 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2105f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern case USB_PORT_FEAT_POWER: 21061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) 21071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_SS_PORT_STAT_POWER; 21081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman else 21091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= USB_PORT_STAT_POWER; 2110cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 2111f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern break; 21121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case USB_PORT_FEAT_BH_PORT_RESET: 21131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* Applicable only for USB3.0 hub */ 21141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 21151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 21161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB_PORT_FEAT_BH_PORT_RESET req not " 21171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 21181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 21191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 21201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* FALLS THROUGH */ 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_RESET: 2122f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* if it's already enabled, disable */ 21231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 21241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 0; 21251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status = 21261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (USB_SS_PORT_STAT_POWER | 21271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_CONNECTION | 21281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_RESET); 21291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 21301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE 2131f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_LOW_SPEED 2132f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern | USB_PORT_STAT_HIGH_SPEED); 2133cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman /* 2134cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * We want to reset device status. All but the 2135cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman * Self powered feature 2136cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman */ 2137cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->dum->devstatus &= 2138cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman (1 << USB_DEVICE_SELF_POWERED); 21391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 21401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * FIXME USB3.0: what is the correct reset signaling 21411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * interval? Is it still 50msec as for HS? 21421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2143cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); 2144f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern /* FALLS THROUGH */ 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 21461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed == HCD_USB3) { 21471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 21481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_SS_PORT_STAT_POWER) != 0) { 21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (1 << wValue); 21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state(dum_hcd); 21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 21521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else 21531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if ((dum_hcd->port_status & 21541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman USB_PORT_STAT_POWER) != 0) { 21551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->port_status |= (1 << wValue); 21561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman set_link_state(dum_hcd); 21571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 21581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 21591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 21601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case GetPortErrorCount: 21611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 21621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 21631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "GetPortErrorCount req not " 21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "supported for USB 2.0 roothub\n"); 21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 21661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 21671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* We'll always return 0 since this is a dummy hub */ 21681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *(__le32 *) buf = cpu_to_le32(0); 21691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 21701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman case SetHubDepth: 21711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (hcd->speed != HCD_USB3) { 21721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "SetHubDepth req not supported for " 21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman "USB 2.0 roothub\n"); 21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto error; 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_dbg(dummy_dev(dum_hcd), 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "hub control req%04x v%04x i%04x l%d\n", 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds typeReq, wValue, wIndex, wLength); 21821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror: 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* "protocol stall" on error */ 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2186cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2187685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern 2188cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if ((dum_hcd->port_status & PORT_C_MASK) != 0) 218918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior usb_hcd_poll_rh_status(hcd); 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_bus_suspend(struct usb_hcd *hcd) 2194391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2196391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 219718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); 21983cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 2199cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irq(&dum_hcd->dum->lock); 2200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_SUSPENDED; 2201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 22023cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_SUSPENDED; 2203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irq(&dum_hcd->dum->lock); 2204391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 2205391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2206391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 220718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_bus_resume(struct usb_hcd *hcd) 2208391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 22103cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 22113cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern 221218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); 2213391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 2214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irq(&dum_hcd->dum->lock); 2215541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) { 2216cfa59dab27d1b282886e7772a8f9548236883892Alan Stern rc = -ESHUTDOWN; 22173cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else { 2218cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 2219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman set_link_state(dum_hcd); 2220cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!list_empty(&dum_hcd->urbp_list)) 2221cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman mod_timer(&dum_hcd->timer, jiffies); 22223cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern hcd->state = HC_STATE_RUNNING; 22233cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } 2224cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irq(&dum_hcd->dum->lock); 22253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 2226391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 223018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline ssize_t show_urb(char *buf, size_t size, struct urb *urb) 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 223218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior int ep = usb_pipeendpoint(urb->pipe); 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 223418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return snprintf(buf, size, 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "urb/%p %s ep%d%s%s len %d/%d\n", 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb, 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; 223818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior switch (urb->dev->speed) { 223918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case USB_SPEED_LOW: 22407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "ls"; 22417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 224218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case USB_SPEED_FULL: 22437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "fs"; 22447c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 224518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case USB_SPEED_HIGH: 22467c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "hs"; 22477c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 224818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case USB_SPEED_SUPER: 22491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman s = "ss"; 22501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman break; 225118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior default: 22527c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "?"; 22537c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; s; }), 225518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "", 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ({ char *s; \ 225718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior switch (usb_pipetype(urb->pipe)) { \ 225818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case PIPE_CONTROL: \ 22597c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = ""; \ 22607c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 226118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case PIPE_BULK: \ 22627c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-bulk"; \ 22637c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 226418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior case PIPE_INTERRUPT: \ 22657c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-int"; \ 22667c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 226718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior default: \ 22687c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman s = "-iso"; \ 22697c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman break; \ 227018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior }; s; }), 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length, urb->transfer_buffer_length); 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 227418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic ssize_t show_urbs(struct device *dev, struct device_attribute *attr, 227518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior char *buf) 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 227718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior struct usb_hcd *hcd = dev_get_drvdata(dev); 2278cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urbp *urbp; 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = 0; 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2283cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) { 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t temp; 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 228718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior temp = show_urb(buf, PAGE_SIZE - size, urbp->urb); 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += temp; 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size += temp; 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2291cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 229518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL); 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd) 22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman init_timer(&dum_hcd->timer); 23001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->timer.function = dummy_timer; 23011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->timer.data = (unsigned long)dum_hcd; 23021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 2303a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dum_hcd->stream_en_ep = 0; 23041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman INIT_LIST_HEAD(&dum_hcd->urbp_list); 23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; 23061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; 23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; 23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG 23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1; 23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif 23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 23131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 23141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); 23151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 23161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2317cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd) 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MASTER side init ... we emulate a root hub that'll only ever 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * talk to one device (the slave side). Also appears in sysfs, 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just like more familiar pci-based HCDs. 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!usb_hcd_is_primary_hcd(hcd)) 23271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return dummy_start_ss(dum_hcd); 23281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2329cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman spin_lock_init(&dum_hcd->dum->lock); 2330cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman init_timer(&dum_hcd->timer); 2331cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->timer.function = dummy_timer; 2332cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->timer.data = (unsigned long)dum_hcd; 2333cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd->rh_state = DUMMY_RH_RUNNING; 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2335cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman INIT_LIST_HEAD(&dum_hcd->urbp_list); 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2337caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern hcd->power_budget = POWER_BUDGET; 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd->state = HC_STATE_RUNNING; 2339685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern hcd->uses_new_polling = 1; 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23415742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG 23425742b0c95026c817d9c266174ca39a909e8d38caAlan Stern hcd->self.otg_port = 1; 23435742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif 23445742b0c95026c817d9c266174ca39a909e8d38caAlan Stern 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ 2346cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_stop(struct usb_hcd *hcd) 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dummy *dum; 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 235318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = hcd_to_dummy_hcd(hcd)->dum; 2354cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); 2355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_gadget_unregister_driver(dum->driver); 2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 236118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_h_get_frame(struct usb_hcd *hcd) 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 236318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior return dummy_g_get_frame(NULL); 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd) 2367cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{ 236814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior hcd->self.sg_tablesize = ~0; 2369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (usb_hcd_is_primary_hcd(hcd)) { 2370cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); 2371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd->dum = &the_controller; 23721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman /* 23731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * Mark the first roothub as being USB 2.0. 23741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * The USB 3.0 roothub will be registered later by 23751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * dummy_hcd_probe() 23761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */ 2377cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hcd->speed = HCD_USB2; 2378cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hcd->self.root_hub->speed = USB_SPEED_HIGH; 23791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } else { 23801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); 23811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd->dum = &the_controller; 23821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hcd->speed = HCD_USB3; 23831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman hcd->self.root_hub->speed = USB_SPEED_SUPER; 2384cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman } 2385cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman return 0; 2386cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman} 2387cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 23881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */ 2389d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, 23901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_host_endpoint **eps, unsigned int num_eps, 23911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman unsigned int num_streams, gfp_t mem_flags) 23921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 2393a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2394a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned long flags; 2395a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int max_stream; 2396a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int ret_streams = num_streams; 2397a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int index; 2398a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int i; 2399a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 2400a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!num_eps) 2401a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return -EINVAL; 2402a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 2403a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2404a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior for (i = 0; i < num_eps; i++) { 2405a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = dummy_get_ep_idx(&eps[i]->desc); 2406a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if ((1 << index) & dum_hcd->stream_en_ep) { 2407a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ret_streams = -EINVAL; 2408a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior goto out; 2409a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2410a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp); 2411a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!max_stream) { 2412a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ret_streams = -EINVAL; 2413a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior goto out; 2414a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2415a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (max_stream < ret_streams) { 2416a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u " 2417a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior "stream IDs.\n", 2418a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior eps[i]->desc.bEndpointAddress, 2419a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior max_stream); 2420a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ret_streams = max_stream; 2421a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2422a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2423a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 2424a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior for (i = 0; i < num_eps; i++) { 2425a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = dummy_get_ep_idx(&eps[i]->desc); 2426a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dum_hcd->stream_en_ep |= 1 << index; 2427a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior set_max_streams_for_pipe(dum_hcd, 2428a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior usb_endpoint_num(&eps[i]->desc), ret_streams); 2429a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2430a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout: 2431a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2432a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return ret_streams; 24331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 24341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 24351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */ 2436d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev, 24371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_host_endpoint **eps, unsigned int num_eps, 24381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman gfp_t mem_flags) 24391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{ 2440a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2441a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned long flags; 2442a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior int ret; 2443a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int index; 2444a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior unsigned int i; 2445a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 2446a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2447a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior for (i = 0; i < num_eps; i++) { 2448a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = dummy_get_ep_idx(&eps[i]->desc); 2449a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior if (!((1 << index) & dum_hcd->stream_en_ep)) { 2450a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ret = -EINVAL; 2451a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior goto out; 2452a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2453a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2454a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior 2455a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior for (i = 0; i < num_eps; i++) { 2456a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior index = dummy_get_ep_idx(&eps[i]->desc); 2457a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior dum_hcd->stream_en_ep &= ~(1 << index); 2458a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior set_max_streams_for_pipe(dum_hcd, 2459a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior usb_endpoint_num(&eps[i]->desc), 0); 2460a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior } 2461a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior ret = 0; 2462a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout: 2463a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2464a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior return ret; 24651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman} 24661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 24671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = { 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = (char *) driver_name, 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .product_desc = "Dummy host controller", 2470cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman .hcd_priv_size = sizeof(struct dummy_hcd), 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .flags = HCD_USB3 | HCD_SHARED, 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2474cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman .reset = dummy_setup, 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = dummy_start, 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = dummy_stop, 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 247818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior .urb_enqueue = dummy_urb_enqueue, 247918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior .urb_dequeue = dummy_urb_dequeue, 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 248118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior .get_frame_number = dummy_h_get_frame, 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 248318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior .hub_status_data = dummy_hub_status, 248418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior .hub_control = dummy_hub_control, 24850c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_suspend = dummy_bus_suspend, 24860c0382e32d46f606951010b202382be14d180a17Alan Stern .bus_resume = dummy_bus_resume, 24871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 24881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .alloc_streams = dummy_alloc_streams, 24891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman .free_streams = dummy_free_streams, 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24928364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev) 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2494cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct usb_hcd *hs_hcd; 24951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman struct usb_hcd *ss_hcd; 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24988364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!mod_data.is_super_speed) 25011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dummy_hcd.flags = HCD_USB2; 2502cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); 2503cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (!hs_hcd) 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2505cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman hs_hcd->has_tt = 1; 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2507cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman retval = usb_add_hcd(hs_hcd, 0, 0); 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 0) { 2509cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_hcd(hs_hcd); 25101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return retval; 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 25131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (mod_data.is_super_speed) { 25141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, 25151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman dev_name(&pdev->dev), hs_hcd); 25161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!ss_hcd) { 25171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman retval = -ENOMEM; 25181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto dealloc_usb2_hcd; 25191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 25201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 25211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman retval = usb_add_hcd(ss_hcd, 0, 0); 25221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (retval) 25231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman goto put_usb3_hcd; 25241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 25251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman return 0; 25261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 25271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd: 25281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(ss_hcd); 25291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd: 25301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(hs_hcd); 25311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.hs_hcd = the_controller.ss_hcd = NULL; 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2535cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev) 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2537cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy *dum; 2538cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman 253918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dum = hcd_to_dummy_hcd(platform_get_drvdata(pdev))->dum; 25401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 25411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (dum->ss_hcd) { 25421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); 25431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); 25441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman } 25451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2546cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 2547cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 25481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman 2549cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman the_controller.hs_hcd = NULL; 25501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman the_controller.ss_hcd = NULL; 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2552d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return 0; 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 255518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state) 2556391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2557391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 2558cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman struct dummy_hcd *dum_hcd; 25593cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern int rc = 0; 2560391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 256118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 2562391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 256318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior hcd = platform_get_drvdata(pdev); 2564cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman dum_hcd = hcd_to_dummy_hcd(hcd); 2565cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { 25663cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); 25673cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern rc = -EBUSY; 25683cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern } else 25693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 25703cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern return rc; 2571391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2572391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 257318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hcd_resume(struct platform_device *pdev) 2574391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{ 2575391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern struct usb_hcd *hcd; 2576391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 257718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior dev_dbg(&pdev->dev, "%s\n", __func__); 2578391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 257918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior hcd = platform_get_drvdata(pdev); 25803cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 258118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior usb_hcd_poll_rh_status(hcd); 2582391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern return 0; 2583391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern} 2584391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern 25853ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = { 2586d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .probe = dummy_hcd_probe, 2587d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern .remove = dummy_hcd_remove, 2588391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .suspend = dummy_hcd_suspend, 2589391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern .resume = dummy_hcd_resume, 25903ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 25913ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = (char *) driver_name, 25923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .owner = THIS_MODULE, 25933ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 2594d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}; 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2596d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/ 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2598a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev; 2599a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev; 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int __init init(void) 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2603a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern int retval = -ENOMEM; 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior if (usb_disabled()) 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2607d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 26087eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman if (!mod_data.is_high_speed && mod_data.is_super_speed) 26097eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman return -EINVAL; 26107eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman 2611a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern the_hcd_pdev = platform_device_alloc(driver_name, -1); 2612a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (!the_hcd_pdev) 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2614a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern the_udc_pdev = platform_device_alloc(gadget_name, -1); 2615a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (!the_udc_pdev) 2616a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_alloc_udc; 2617d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2618a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_driver_register(&dummy_hcd_driver); 2619a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern if (retval < 0) 2620a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_register_hcd_driver; 2621a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_driver_register(&dummy_udc_driver); 2622d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2623d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern goto err_register_udc_driver; 2624d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2625a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_device_add(the_hcd_pdev); 2626d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2627a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_add_hcd; 26281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman if (!the_controller.hs_hcd || 26291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman (!the_controller.ss_hcd && mod_data.is_super_speed)) { 2630865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior /* 2631865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * The hcd was added successfully but its probe function failed 2632865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * for some reason. 2633865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior */ 2634865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior retval = -EINVAL; 2635865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior goto err_add_udc; 2636865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior } 2637a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern retval = platform_device_add(the_udc_pdev); 2638d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern if (retval < 0) 2639a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern goto err_add_udc; 2640865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior if (!platform_get_drvdata(the_udc_pdev)) { 2641865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior /* 2642865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * The udc was added successfully but its probe function failed 2643865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior * for some reason. 2644865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior */ 2645865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior retval = -EINVAL; 2646865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior goto err_probe_udc; 2647865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior } 2648d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern return retval; 2649d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern 2650865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc: 2651865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior platform_device_del(the_udc_pdev); 2652a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc: 2653a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_del(the_hcd_pdev); 2654a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd: 2655a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_udc_driver); 2656d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver: 2657a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_hcd_driver); 2658a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver: 2659a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_put(the_udc_pdev); 2660a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc: 2661a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_put(the_hcd_pdev); 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 266418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiormodule_init(init); 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 266618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void __exit cleanup(void) 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2668a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_unregister(the_udc_pdev); 2669a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_device_unregister(the_hcd_pdev); 2670a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_udc_driver); 2671a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern platform_driver_unregister(&dummy_hcd_driver); 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 267318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiormodule_exit(cleanup); 2674