at v2.6.32-rc2 385 lines 10 kB view raw
1/* 2 * f_loopback.c - USB peripheral loopback configuration driver 3 * 4 * Copyright (C) 2003-2008 David Brownell 5 * Copyright (C) 2008 by Nokia Corporation 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22/* #define VERBOSE_DEBUG */ 23 24#include <linux/kernel.h> 25#include <linux/device.h> 26 27#include "g_zero.h" 28#include "gadget_chips.h" 29 30 31/* 32 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, 33 * 34 * This takes messages of various sizes written OUT to a device, and loops 35 * them back so they can be read IN from it. It has been used by certain 36 * test applications. It supports limited testing of data queueing logic. 37 * 38 * 39 * This is currently packaged as a configuration driver, which can't be 40 * combined with other functions to make composite devices. However, it 41 * can be combined with other independent configurations. 42 */ 43struct f_loopback { 44 struct usb_function function; 45 46 struct usb_ep *in_ep; 47 struct usb_ep *out_ep; 48}; 49 50static inline struct f_loopback *func_to_loop(struct usb_function *f) 51{ 52 return container_of(f, struct f_loopback, function); 53} 54 55static unsigned qlen = 32; 56module_param(qlen, uint, 0); 57MODULE_PARM_DESC(qlenn, "depth of loopback queue"); 58 59/*-------------------------------------------------------------------------*/ 60 61static struct usb_interface_descriptor loopback_intf = { 62 .bLength = sizeof loopback_intf, 63 .bDescriptorType = USB_DT_INTERFACE, 64 65 .bNumEndpoints = 2, 66 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 67 /* .iInterface = DYNAMIC */ 68}; 69 70/* full speed support: */ 71 72static struct usb_endpoint_descriptor fs_loop_source_desc = { 73 .bLength = USB_DT_ENDPOINT_SIZE, 74 .bDescriptorType = USB_DT_ENDPOINT, 75 76 .bEndpointAddress = USB_DIR_IN, 77 .bmAttributes = USB_ENDPOINT_XFER_BULK, 78}; 79 80static struct usb_endpoint_descriptor fs_loop_sink_desc = { 81 .bLength = USB_DT_ENDPOINT_SIZE, 82 .bDescriptorType = USB_DT_ENDPOINT, 83 84 .bEndpointAddress = USB_DIR_OUT, 85 .bmAttributes = USB_ENDPOINT_XFER_BULK, 86}; 87 88static struct usb_descriptor_header *fs_loopback_descs[] = { 89 (struct usb_descriptor_header *) &loopback_intf, 90 (struct usb_descriptor_header *) &fs_loop_sink_desc, 91 (struct usb_descriptor_header *) &fs_loop_source_desc, 92 NULL, 93}; 94 95/* high speed support: */ 96 97static struct usb_endpoint_descriptor hs_loop_source_desc = { 98 .bLength = USB_DT_ENDPOINT_SIZE, 99 .bDescriptorType = USB_DT_ENDPOINT, 100 101 .bmAttributes = USB_ENDPOINT_XFER_BULK, 102 .wMaxPacketSize = cpu_to_le16(512), 103}; 104 105static struct usb_endpoint_descriptor hs_loop_sink_desc = { 106 .bLength = USB_DT_ENDPOINT_SIZE, 107 .bDescriptorType = USB_DT_ENDPOINT, 108 109 .bmAttributes = USB_ENDPOINT_XFER_BULK, 110 .wMaxPacketSize = cpu_to_le16(512), 111}; 112 113static struct usb_descriptor_header *hs_loopback_descs[] = { 114 (struct usb_descriptor_header *) &loopback_intf, 115 (struct usb_descriptor_header *) &hs_loop_source_desc, 116 (struct usb_descriptor_header *) &hs_loop_sink_desc, 117 NULL, 118}; 119 120/* function-specific strings: */ 121 122static struct usb_string strings_loopback[] = { 123 [0].s = "loop input to output", 124 { } /* end of list */ 125}; 126 127static struct usb_gadget_strings stringtab_loop = { 128 .language = 0x0409, /* en-us */ 129 .strings = strings_loopback, 130}; 131 132static struct usb_gadget_strings *loopback_strings[] = { 133 &stringtab_loop, 134 NULL, 135}; 136 137/*-------------------------------------------------------------------------*/ 138 139static int __init 140loopback_bind(struct usb_configuration *c, struct usb_function *f) 141{ 142 struct usb_composite_dev *cdev = c->cdev; 143 struct f_loopback *loop = func_to_loop(f); 144 int id; 145 146 /* allocate interface ID(s) */ 147 id = usb_interface_id(c, f); 148 if (id < 0) 149 return id; 150 loopback_intf.bInterfaceNumber = id; 151 152 /* allocate endpoints */ 153 154 loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); 155 if (!loop->in_ep) { 156autoconf_fail: 157 ERROR(cdev, "%s: can't autoconfigure on %s\n", 158 f->name, cdev->gadget->name); 159 return -ENODEV; 160 } 161 loop->in_ep->driver_data = cdev; /* claim */ 162 163 loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc); 164 if (!loop->out_ep) 165 goto autoconf_fail; 166 loop->out_ep->driver_data = cdev; /* claim */ 167 168 /* support high speed hardware */ 169 if (gadget_is_dualspeed(c->cdev->gadget)) { 170 hs_loop_source_desc.bEndpointAddress = 171 fs_loop_source_desc.bEndpointAddress; 172 hs_loop_sink_desc.bEndpointAddress = 173 fs_loop_sink_desc.bEndpointAddress; 174 f->hs_descriptors = hs_loopback_descs; 175 } 176 177 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", 178 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", 179 f->name, loop->in_ep->name, loop->out_ep->name); 180 return 0; 181} 182 183static void 184loopback_unbind(struct usb_configuration *c, struct usb_function *f) 185{ 186 kfree(func_to_loop(f)); 187} 188 189static void loopback_complete(struct usb_ep *ep, struct usb_request *req) 190{ 191 struct f_loopback *loop = ep->driver_data; 192 struct usb_composite_dev *cdev = loop->function.config->cdev; 193 int status = req->status; 194 195 switch (status) { 196 197 case 0: /* normal completion? */ 198 if (ep == loop->out_ep) { 199 /* loop this OUT packet back IN to the host */ 200 req->zero = (req->actual < req->length); 201 req->length = req->actual; 202 status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC); 203 if (status == 0) 204 return; 205 206 /* "should never get here" */ 207 ERROR(cdev, "can't loop %s to %s: %d\n", 208 ep->name, loop->in_ep->name, 209 status); 210 } 211 212 /* queue the buffer for some later OUT packet */ 213 req->length = buflen; 214 status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); 215 if (status == 0) 216 return; 217 218 /* "should never get here" */ 219 /* FALLTHROUGH */ 220 221 default: 222 ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name, 223 status, req->actual, req->length); 224 /* FALLTHROUGH */ 225 226 /* NOTE: since this driver doesn't maintain an explicit record 227 * of requests it submitted (just maintains qlen count), we 228 * rely on the hardware driver to clean up on disconnect or 229 * endpoint disable. 230 */ 231 case -ECONNABORTED: /* hardware forced ep reset */ 232 case -ECONNRESET: /* request dequeued */ 233 case -ESHUTDOWN: /* disconnect from host */ 234 free_ep_req(ep, req); 235 return; 236 } 237} 238 239static void disable_loopback(struct f_loopback *loop) 240{ 241 struct usb_composite_dev *cdev; 242 243 cdev = loop->function.config->cdev; 244 disable_endpoints(cdev, loop->in_ep, loop->out_ep); 245 VDBG(cdev, "%s disabled\n", loop->function.name); 246} 247 248static int 249enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) 250{ 251 int result = 0; 252 const struct usb_endpoint_descriptor *src, *sink; 253 struct usb_ep *ep; 254 struct usb_request *req; 255 unsigned i; 256 257 src = ep_choose(cdev->gadget, 258 &hs_loop_source_desc, &fs_loop_source_desc); 259 sink = ep_choose(cdev->gadget, 260 &hs_loop_sink_desc, &fs_loop_sink_desc); 261 262 /* one endpoint writes data back IN to the host */ 263 ep = loop->in_ep; 264 result = usb_ep_enable(ep, src); 265 if (result < 0) 266 return result; 267 ep->driver_data = loop; 268 269 /* one endpoint just reads OUT packets */ 270 ep = loop->out_ep; 271 result = usb_ep_enable(ep, sink); 272 if (result < 0) { 273fail0: 274 ep = loop->in_ep; 275 usb_ep_disable(ep); 276 ep->driver_data = NULL; 277 return result; 278 } 279 ep->driver_data = loop; 280 281 /* allocate a bunch of read buffers and queue them all at once. 282 * we buffer at most 'qlen' transfers; fewer if any need more 283 * than 'buflen' bytes each. 284 */ 285 for (i = 0; i < qlen && result == 0; i++) { 286 req = alloc_ep_req(ep); 287 if (req) { 288 req->complete = loopback_complete; 289 result = usb_ep_queue(ep, req, GFP_ATOMIC); 290 if (result) 291 ERROR(cdev, "%s queue req --> %d\n", 292 ep->name, result); 293 } else { 294 usb_ep_disable(ep); 295 ep->driver_data = NULL; 296 result = -ENOMEM; 297 goto fail0; 298 } 299 } 300 301 DBG(cdev, "%s enabled\n", loop->function.name); 302 return result; 303} 304 305static int loopback_set_alt(struct usb_function *f, 306 unsigned intf, unsigned alt) 307{ 308 struct f_loopback *loop = func_to_loop(f); 309 struct usb_composite_dev *cdev = f->config->cdev; 310 311 /* we know alt is zero */ 312 if (loop->in_ep->driver_data) 313 disable_loopback(loop); 314 return enable_loopback(cdev, loop); 315} 316 317static void loopback_disable(struct usb_function *f) 318{ 319 struct f_loopback *loop = func_to_loop(f); 320 321 disable_loopback(loop); 322} 323 324/*-------------------------------------------------------------------------*/ 325 326static int __init loopback_bind_config(struct usb_configuration *c) 327{ 328 struct f_loopback *loop; 329 int status; 330 331 loop = kzalloc(sizeof *loop, GFP_KERNEL); 332 if (!loop) 333 return -ENOMEM; 334 335 loop->function.name = "loopback"; 336 loop->function.descriptors = fs_loopback_descs; 337 loop->function.bind = loopback_bind; 338 loop->function.unbind = loopback_unbind; 339 loop->function.set_alt = loopback_set_alt; 340 loop->function.disable = loopback_disable; 341 342 status = usb_add_function(c, &loop->function); 343 if (status) 344 kfree(loop); 345 return status; 346} 347 348static struct usb_configuration loopback_driver = { 349 .label = "loopback", 350 .strings = loopback_strings, 351 .bind = loopback_bind_config, 352 .bConfigurationValue = 2, 353 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 354 /* .iConfiguration = DYNAMIC */ 355}; 356 357/** 358 * loopback_add - add a loopback testing configuration to a device 359 * @cdev: the device to support the loopback configuration 360 */ 361int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) 362{ 363 int id; 364 365 /* allocate string ID(s) */ 366 id = usb_string_id(cdev); 367 if (id < 0) 368 return id; 369 strings_loopback[0].id = id; 370 371 loopback_intf.iInterface = id; 372 loopback_driver.iConfiguration = id; 373 374 /* support autoresume for remote wakeup testing */ 375 if (autoresume) 376 sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 377 378 /* support OTG systems */ 379 if (gadget_is_otg(cdev->gadget)) { 380 loopback_driver.descriptors = otg_desc; 381 loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 382 } 383 384 return usb_add_config(cdev, &loopback_driver); 385}