at v3.1-rc3 439 lines 12 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/slab.h> 25#include <linux/kernel.h> 26#include <linux/device.h> 27 28#include "g_zero.h" 29#include "gadget_chips.h" 30 31 32/* 33 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, 34 * 35 * This takes messages of various sizes written OUT to a device, and loops 36 * them back so they can be read IN from it. It has been used by certain 37 * test applications. It supports limited testing of data queueing logic. 38 * 39 * 40 * This is currently packaged as a configuration driver, which can't be 41 * combined with other functions to make composite devices. However, it 42 * can be combined with other independent configurations. 43 */ 44struct f_loopback { 45 struct usb_function function; 46 47 struct usb_ep *in_ep; 48 struct usb_ep *out_ep; 49}; 50 51static inline struct f_loopback *func_to_loop(struct usb_function *f) 52{ 53 return container_of(f, struct f_loopback, function); 54} 55 56static unsigned qlen = 32; 57module_param(qlen, uint, 0); 58MODULE_PARM_DESC(qlenn, "depth of loopback queue"); 59 60/*-------------------------------------------------------------------------*/ 61 62static struct usb_interface_descriptor loopback_intf = { 63 .bLength = sizeof loopback_intf, 64 .bDescriptorType = USB_DT_INTERFACE, 65 66 .bNumEndpoints = 2, 67 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 68 /* .iInterface = DYNAMIC */ 69}; 70 71/* full speed support: */ 72 73static struct usb_endpoint_descriptor fs_loop_source_desc = { 74 .bLength = USB_DT_ENDPOINT_SIZE, 75 .bDescriptorType = USB_DT_ENDPOINT, 76 77 .bEndpointAddress = USB_DIR_IN, 78 .bmAttributes = USB_ENDPOINT_XFER_BULK, 79}; 80 81static struct usb_endpoint_descriptor fs_loop_sink_desc = { 82 .bLength = USB_DT_ENDPOINT_SIZE, 83 .bDescriptorType = USB_DT_ENDPOINT, 84 85 .bEndpointAddress = USB_DIR_OUT, 86 .bmAttributes = USB_ENDPOINT_XFER_BULK, 87}; 88 89static struct usb_descriptor_header *fs_loopback_descs[] = { 90 (struct usb_descriptor_header *) &loopback_intf, 91 (struct usb_descriptor_header *) &fs_loop_sink_desc, 92 (struct usb_descriptor_header *) &fs_loop_source_desc, 93 NULL, 94}; 95 96/* high speed support: */ 97 98static struct usb_endpoint_descriptor hs_loop_source_desc = { 99 .bLength = USB_DT_ENDPOINT_SIZE, 100 .bDescriptorType = USB_DT_ENDPOINT, 101 102 .bmAttributes = USB_ENDPOINT_XFER_BULK, 103 .wMaxPacketSize = cpu_to_le16(512), 104}; 105 106static struct usb_endpoint_descriptor hs_loop_sink_desc = { 107 .bLength = USB_DT_ENDPOINT_SIZE, 108 .bDescriptorType = USB_DT_ENDPOINT, 109 110 .bmAttributes = USB_ENDPOINT_XFER_BULK, 111 .wMaxPacketSize = cpu_to_le16(512), 112}; 113 114static struct usb_descriptor_header *hs_loopback_descs[] = { 115 (struct usb_descriptor_header *) &loopback_intf, 116 (struct usb_descriptor_header *) &hs_loop_source_desc, 117 (struct usb_descriptor_header *) &hs_loop_sink_desc, 118 NULL, 119}; 120 121/* super speed support: */ 122 123static struct usb_endpoint_descriptor ss_loop_source_desc = { 124 .bLength = USB_DT_ENDPOINT_SIZE, 125 .bDescriptorType = USB_DT_ENDPOINT, 126 127 .bmAttributes = USB_ENDPOINT_XFER_BULK, 128 .wMaxPacketSize = cpu_to_le16(1024), 129}; 130 131struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { 132 .bLength = USB_DT_SS_EP_COMP_SIZE, 133 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 134 .bMaxBurst = 0, 135 .bmAttributes = 0, 136 .wBytesPerInterval = 0, 137}; 138 139static struct usb_endpoint_descriptor ss_loop_sink_desc = { 140 .bLength = USB_DT_ENDPOINT_SIZE, 141 .bDescriptorType = USB_DT_ENDPOINT, 142 143 .bmAttributes = USB_ENDPOINT_XFER_BULK, 144 .wMaxPacketSize = cpu_to_le16(1024), 145}; 146 147struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { 148 .bLength = USB_DT_SS_EP_COMP_SIZE, 149 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 150 .bMaxBurst = 0, 151 .bmAttributes = 0, 152 .wBytesPerInterval = 0, 153}; 154 155static struct usb_descriptor_header *ss_loopback_descs[] = { 156 (struct usb_descriptor_header *) &loopback_intf, 157 (struct usb_descriptor_header *) &ss_loop_source_desc, 158 (struct usb_descriptor_header *) &ss_loop_source_comp_desc, 159 (struct usb_descriptor_header *) &ss_loop_sink_desc, 160 (struct usb_descriptor_header *) &ss_loop_sink_comp_desc, 161 NULL, 162}; 163 164/* function-specific strings: */ 165 166static struct usb_string strings_loopback[] = { 167 [0].s = "loop input to output", 168 { } /* end of list */ 169}; 170 171static struct usb_gadget_strings stringtab_loop = { 172 .language = 0x0409, /* en-us */ 173 .strings = strings_loopback, 174}; 175 176static struct usb_gadget_strings *loopback_strings[] = { 177 &stringtab_loop, 178 NULL, 179}; 180 181/*-------------------------------------------------------------------------*/ 182 183static int __init 184loopback_bind(struct usb_configuration *c, struct usb_function *f) 185{ 186 struct usb_composite_dev *cdev = c->cdev; 187 struct f_loopback *loop = func_to_loop(f); 188 int id; 189 190 /* allocate interface ID(s) */ 191 id = usb_interface_id(c, f); 192 if (id < 0) 193 return id; 194 loopback_intf.bInterfaceNumber = id; 195 196 /* allocate endpoints */ 197 198 loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); 199 if (!loop->in_ep) { 200autoconf_fail: 201 ERROR(cdev, "%s: can't autoconfigure on %s\n", 202 f->name, cdev->gadget->name); 203 return -ENODEV; 204 } 205 loop->in_ep->driver_data = cdev; /* claim */ 206 207 loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc); 208 if (!loop->out_ep) 209 goto autoconf_fail; 210 loop->out_ep->driver_data = cdev; /* claim */ 211 212 /* support high speed hardware */ 213 if (gadget_is_dualspeed(c->cdev->gadget)) { 214 hs_loop_source_desc.bEndpointAddress = 215 fs_loop_source_desc.bEndpointAddress; 216 hs_loop_sink_desc.bEndpointAddress = 217 fs_loop_sink_desc.bEndpointAddress; 218 f->hs_descriptors = hs_loopback_descs; 219 } 220 221 /* support super speed hardware */ 222 if (gadget_is_superspeed(c->cdev->gadget)) { 223 ss_loop_source_desc.bEndpointAddress = 224 fs_loop_source_desc.bEndpointAddress; 225 ss_loop_sink_desc.bEndpointAddress = 226 fs_loop_sink_desc.bEndpointAddress; 227 f->ss_descriptors = ss_loopback_descs; 228 } 229 230 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", 231 (gadget_is_superspeed(c->cdev->gadget) ? "super" : 232 (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), 233 f->name, loop->in_ep->name, loop->out_ep->name); 234 return 0; 235} 236 237static void 238loopback_unbind(struct usb_configuration *c, struct usb_function *f) 239{ 240 kfree(func_to_loop(f)); 241} 242 243static void loopback_complete(struct usb_ep *ep, struct usb_request *req) 244{ 245 struct f_loopback *loop = ep->driver_data; 246 struct usb_composite_dev *cdev = loop->function.config->cdev; 247 int status = req->status; 248 249 switch (status) { 250 251 case 0: /* normal completion? */ 252 if (ep == loop->out_ep) { 253 /* loop this OUT packet back IN to the host */ 254 req->zero = (req->actual < req->length); 255 req->length = req->actual; 256 status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC); 257 if (status == 0) 258 return; 259 260 /* "should never get here" */ 261 ERROR(cdev, "can't loop %s to %s: %d\n", 262 ep->name, loop->in_ep->name, 263 status); 264 } 265 266 /* queue the buffer for some later OUT packet */ 267 req->length = buflen; 268 status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); 269 if (status == 0) 270 return; 271 272 /* "should never get here" */ 273 /* FALLTHROUGH */ 274 275 default: 276 ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name, 277 status, req->actual, req->length); 278 /* FALLTHROUGH */ 279 280 /* NOTE: since this driver doesn't maintain an explicit record 281 * of requests it submitted (just maintains qlen count), we 282 * rely on the hardware driver to clean up on disconnect or 283 * endpoint disable. 284 */ 285 case -ECONNABORTED: /* hardware forced ep reset */ 286 case -ECONNRESET: /* request dequeued */ 287 case -ESHUTDOWN: /* disconnect from host */ 288 free_ep_req(ep, req); 289 return; 290 } 291} 292 293static void disable_loopback(struct f_loopback *loop) 294{ 295 struct usb_composite_dev *cdev; 296 297 cdev = loop->function.config->cdev; 298 disable_endpoints(cdev, loop->in_ep, loop->out_ep); 299 VDBG(cdev, "%s disabled\n", loop->function.name); 300} 301 302static int 303enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) 304{ 305 int result = 0; 306 struct usb_ep *ep; 307 struct usb_request *req; 308 unsigned i; 309 310 /* one endpoint writes data back IN to the host */ 311 ep = loop->in_ep; 312 result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); 313 if (result) 314 return result; 315 result = usb_ep_enable(ep); 316 if (result < 0) 317 return result; 318 ep->driver_data = loop; 319 320 /* one endpoint just reads OUT packets */ 321 ep = loop->out_ep; 322 result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); 323 if (result) 324 goto fail0; 325 326 result = usb_ep_enable(ep); 327 if (result < 0) { 328fail0: 329 ep = loop->in_ep; 330 usb_ep_disable(ep); 331 ep->driver_data = NULL; 332 return result; 333 } 334 ep->driver_data = loop; 335 336 /* allocate a bunch of read buffers and queue them all at once. 337 * we buffer at most 'qlen' transfers; fewer if any need more 338 * than 'buflen' bytes each. 339 */ 340 for (i = 0; i < qlen && result == 0; i++) { 341 req = alloc_ep_req(ep); 342 if (req) { 343 req->complete = loopback_complete; 344 result = usb_ep_queue(ep, req, GFP_ATOMIC); 345 if (result) 346 ERROR(cdev, "%s queue req --> %d\n", 347 ep->name, result); 348 } else { 349 usb_ep_disable(ep); 350 ep->driver_data = NULL; 351 result = -ENOMEM; 352 goto fail0; 353 } 354 } 355 356 DBG(cdev, "%s enabled\n", loop->function.name); 357 return result; 358} 359 360static int loopback_set_alt(struct usb_function *f, 361 unsigned intf, unsigned alt) 362{ 363 struct f_loopback *loop = func_to_loop(f); 364 struct usb_composite_dev *cdev = f->config->cdev; 365 366 /* we know alt is zero */ 367 if (loop->in_ep->driver_data) 368 disable_loopback(loop); 369 return enable_loopback(cdev, loop); 370} 371 372static void loopback_disable(struct usb_function *f) 373{ 374 struct f_loopback *loop = func_to_loop(f); 375 376 disable_loopback(loop); 377} 378 379/*-------------------------------------------------------------------------*/ 380 381static int __init loopback_bind_config(struct usb_configuration *c) 382{ 383 struct f_loopback *loop; 384 int status; 385 386 loop = kzalloc(sizeof *loop, GFP_KERNEL); 387 if (!loop) 388 return -ENOMEM; 389 390 loop->function.name = "loopback"; 391 loop->function.descriptors = fs_loopback_descs; 392 loop->function.bind = loopback_bind; 393 loop->function.unbind = loopback_unbind; 394 loop->function.set_alt = loopback_set_alt; 395 loop->function.disable = loopback_disable; 396 397 status = usb_add_function(c, &loop->function); 398 if (status) 399 kfree(loop); 400 return status; 401} 402 403static struct usb_configuration loopback_driver = { 404 .label = "loopback", 405 .strings = loopback_strings, 406 .bConfigurationValue = 2, 407 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 408 /* .iConfiguration = DYNAMIC */ 409}; 410 411/** 412 * loopback_add - add a loopback testing configuration to a device 413 * @cdev: the device to support the loopback configuration 414 */ 415int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) 416{ 417 int id; 418 419 /* allocate string ID(s) */ 420 id = usb_string_id(cdev); 421 if (id < 0) 422 return id; 423 strings_loopback[0].id = id; 424 425 loopback_intf.iInterface = id; 426 loopback_driver.iConfiguration = id; 427 428 /* support autoresume for remote wakeup testing */ 429 if (autoresume) 430 sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 431 432 /* support OTG systems */ 433 if (gadget_is_otg(cdev->gadget)) { 434 loopback_driver.descriptors = otg_desc; 435 loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 436 } 437 438 return usb_add_config(cdev, &loopback_driver, loopback_bind_config); 439}