Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.0 493 lines 14 kB view raw
1/* 2 * f_obex.c -- USB CDC OBEX function driver 3 * 4 * Copyright (C) 2008 Nokia Corporation 5 * Contact: Felipe Balbi <felipe.balbi@nokia.com> 6 * 7 * Based on f_acm.c by Al Borchers and David Brownell. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24/* #define VERBOSE_DEBUG */ 25 26#include <linux/slab.h> 27#include <linux/kernel.h> 28#include <linux/device.h> 29 30#include "u_serial.h" 31#include "gadget_chips.h" 32 33 34/* 35 * This CDC OBEX function support just packages a TTY-ish byte stream. 36 * A user mode server will put it into "raw" mode and handle all the 37 * relevant protocol details ... this is just a kernel passthrough. 38 * When possible, we prevent gadget enumeration until that server is 39 * ready to handle the commands. 40 */ 41 42struct obex_ep_descs { 43 struct usb_endpoint_descriptor *obex_in; 44 struct usb_endpoint_descriptor *obex_out; 45}; 46 47struct f_obex { 48 struct gserial port; 49 u8 ctrl_id; 50 u8 data_id; 51 u8 port_num; 52 u8 can_activate; 53 54 struct obex_ep_descs fs; 55 struct obex_ep_descs hs; 56}; 57 58static inline struct f_obex *func_to_obex(struct usb_function *f) 59{ 60 return container_of(f, struct f_obex, port.func); 61} 62 63static inline struct f_obex *port_to_obex(struct gserial *p) 64{ 65 return container_of(p, struct f_obex, port); 66} 67 68/*-------------------------------------------------------------------------*/ 69 70#define OBEX_CTRL_IDX 0 71#define OBEX_DATA_IDX 1 72 73static struct usb_string obex_string_defs[] = { 74 [OBEX_CTRL_IDX].s = "CDC Object Exchange (OBEX)", 75 [OBEX_DATA_IDX].s = "CDC OBEX Data", 76 { }, /* end of list */ 77}; 78 79static struct usb_gadget_strings obex_string_table = { 80 .language = 0x0409, /* en-US */ 81 .strings = obex_string_defs, 82}; 83 84static struct usb_gadget_strings *obex_strings[] = { 85 &obex_string_table, 86 NULL, 87}; 88 89/*-------------------------------------------------------------------------*/ 90 91static struct usb_interface_descriptor obex_control_intf __initdata = { 92 .bLength = sizeof(obex_control_intf), 93 .bDescriptorType = USB_DT_INTERFACE, 94 .bInterfaceNumber = 0, 95 96 .bAlternateSetting = 0, 97 .bNumEndpoints = 0, 98 .bInterfaceClass = USB_CLASS_COMM, 99 .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, 100}; 101 102static struct usb_interface_descriptor obex_data_nop_intf __initdata = { 103 .bLength = sizeof(obex_data_nop_intf), 104 .bDescriptorType = USB_DT_INTERFACE, 105 .bInterfaceNumber = 1, 106 107 .bAlternateSetting = 0, 108 .bNumEndpoints = 0, 109 .bInterfaceClass = USB_CLASS_CDC_DATA, 110}; 111 112static struct usb_interface_descriptor obex_data_intf __initdata = { 113 .bLength = sizeof(obex_data_intf), 114 .bDescriptorType = USB_DT_INTERFACE, 115 .bInterfaceNumber = 2, 116 117 .bAlternateSetting = 1, 118 .bNumEndpoints = 2, 119 .bInterfaceClass = USB_CLASS_CDC_DATA, 120}; 121 122static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = { 123 .bLength = sizeof(obex_cdc_header_desc), 124 .bDescriptorType = USB_DT_CS_INTERFACE, 125 .bDescriptorSubType = USB_CDC_HEADER_TYPE, 126 .bcdCDC = cpu_to_le16(0x0120), 127}; 128 129static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { 130 .bLength = sizeof(obex_cdc_union_desc), 131 .bDescriptorType = USB_DT_CS_INTERFACE, 132 .bDescriptorSubType = USB_CDC_UNION_TYPE, 133 .bMasterInterface0 = 1, 134 .bSlaveInterface0 = 2, 135}; 136 137static struct usb_cdc_obex_desc obex_desc __initdata = { 138 .bLength = sizeof(obex_desc), 139 .bDescriptorType = USB_DT_CS_INTERFACE, 140 .bDescriptorSubType = USB_CDC_OBEX_TYPE, 141 .bcdVersion = cpu_to_le16(0x0100), 142}; 143 144/* High-Speed Support */ 145 146static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { 147 .bLength = USB_DT_ENDPOINT_SIZE, 148 .bDescriptorType = USB_DT_ENDPOINT, 149 150 .bEndpointAddress = USB_DIR_OUT, 151 .bmAttributes = USB_ENDPOINT_XFER_BULK, 152 .wMaxPacketSize = cpu_to_le16(512), 153}; 154 155static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { 156 .bLength = USB_DT_ENDPOINT_SIZE, 157 .bDescriptorType = USB_DT_ENDPOINT, 158 159 .bEndpointAddress = USB_DIR_IN, 160 .bmAttributes = USB_ENDPOINT_XFER_BULK, 161 .wMaxPacketSize = cpu_to_le16(512), 162}; 163 164static struct usb_descriptor_header *hs_function[] __initdata = { 165 (struct usb_descriptor_header *) &obex_control_intf, 166 (struct usb_descriptor_header *) &obex_cdc_header_desc, 167 (struct usb_descriptor_header *) &obex_desc, 168 (struct usb_descriptor_header *) &obex_cdc_union_desc, 169 170 (struct usb_descriptor_header *) &obex_data_nop_intf, 171 (struct usb_descriptor_header *) &obex_data_intf, 172 (struct usb_descriptor_header *) &obex_hs_ep_in_desc, 173 (struct usb_descriptor_header *) &obex_hs_ep_out_desc, 174 NULL, 175}; 176 177/* Full-Speed Support */ 178 179static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { 180 .bLength = USB_DT_ENDPOINT_SIZE, 181 .bDescriptorType = USB_DT_ENDPOINT, 182 183 .bEndpointAddress = USB_DIR_IN, 184 .bmAttributes = USB_ENDPOINT_XFER_BULK, 185}; 186 187static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { 188 .bLength = USB_DT_ENDPOINT_SIZE, 189 .bDescriptorType = USB_DT_ENDPOINT, 190 191 .bEndpointAddress = USB_DIR_OUT, 192 .bmAttributes = USB_ENDPOINT_XFER_BULK, 193}; 194 195static struct usb_descriptor_header *fs_function[] __initdata = { 196 (struct usb_descriptor_header *) &obex_control_intf, 197 (struct usb_descriptor_header *) &obex_cdc_header_desc, 198 (struct usb_descriptor_header *) &obex_desc, 199 (struct usb_descriptor_header *) &obex_cdc_union_desc, 200 201 (struct usb_descriptor_header *) &obex_data_nop_intf, 202 (struct usb_descriptor_header *) &obex_data_intf, 203 (struct usb_descriptor_header *) &obex_fs_ep_in_desc, 204 (struct usb_descriptor_header *) &obex_fs_ep_out_desc, 205 NULL, 206}; 207 208/*-------------------------------------------------------------------------*/ 209 210static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) 211{ 212 struct f_obex *obex = func_to_obex(f); 213 struct usb_composite_dev *cdev = f->config->cdev; 214 215 if (intf == obex->ctrl_id) { 216 if (alt != 0) 217 goto fail; 218 /* NOP */ 219 DBG(cdev, "reset obex ttyGS%d control\n", obex->port_num); 220 221 } else if (intf == obex->data_id) { 222 if (alt > 1) 223 goto fail; 224 225 if (obex->port.in->driver_data) { 226 DBG(cdev, "reset obex ttyGS%d\n", obex->port_num); 227 gserial_disconnect(&obex->port); 228 } 229 230 if (!obex->port.in_desc) { 231 DBG(cdev, "init obex ttyGS%d\n", obex->port_num); 232 obex->port.in_desc = ep_choose(cdev->gadget, 233 obex->hs.obex_in, obex->fs.obex_in); 234 obex->port.out_desc = ep_choose(cdev->gadget, 235 obex->hs.obex_out, obex->fs.obex_out); 236 } 237 238 if (alt == 1) { 239 DBG(cdev, "activate obex ttyGS%d\n", obex->port_num); 240 gserial_connect(&obex->port, obex->port_num); 241 } 242 243 } else 244 goto fail; 245 246 return 0; 247 248fail: 249 return -EINVAL; 250} 251 252static int obex_get_alt(struct usb_function *f, unsigned intf) 253{ 254 struct f_obex *obex = func_to_obex(f); 255 256 if (intf == obex->ctrl_id) 257 return 0; 258 259 return obex->port.in->driver_data ? 1 : 0; 260} 261 262static void obex_disable(struct usb_function *f) 263{ 264 struct f_obex *obex = func_to_obex(f); 265 struct usb_composite_dev *cdev = f->config->cdev; 266 267 DBG(cdev, "obex ttyGS%d disable\n", obex->port_num); 268 gserial_disconnect(&obex->port); 269} 270 271/*-------------------------------------------------------------------------*/ 272 273static void obex_connect(struct gserial *g) 274{ 275 struct f_obex *obex = port_to_obex(g); 276 struct usb_composite_dev *cdev = g->func.config->cdev; 277 int status; 278 279 if (!obex->can_activate) 280 return; 281 282 status = usb_function_activate(&g->func); 283 if (status) 284 DBG(cdev, "obex ttyGS%d function activate --> %d\n", 285 obex->port_num, status); 286} 287 288static void obex_disconnect(struct gserial *g) 289{ 290 struct f_obex *obex = port_to_obex(g); 291 struct usb_composite_dev *cdev = g->func.config->cdev; 292 int status; 293 294 if (!obex->can_activate) 295 return; 296 297 status = usb_function_deactivate(&g->func); 298 if (status) 299 DBG(cdev, "obex ttyGS%d function deactivate --> %d\n", 300 obex->port_num, status); 301} 302 303/*-------------------------------------------------------------------------*/ 304 305static int __init 306obex_bind(struct usb_configuration *c, struct usb_function *f) 307{ 308 struct usb_composite_dev *cdev = c->cdev; 309 struct f_obex *obex = func_to_obex(f); 310 int status; 311 struct usb_ep *ep; 312 313 /* allocate instance-specific interface IDs, and patch descriptors */ 314 315 status = usb_interface_id(c, f); 316 if (status < 0) 317 goto fail; 318 obex->ctrl_id = status; 319 320 obex_control_intf.bInterfaceNumber = status; 321 obex_cdc_union_desc.bMasterInterface0 = status; 322 323 status = usb_interface_id(c, f); 324 if (status < 0) 325 goto fail; 326 obex->data_id = status; 327 328 obex_data_nop_intf.bInterfaceNumber = status; 329 obex_data_intf.bInterfaceNumber = status; 330 obex_cdc_union_desc.bSlaveInterface0 = status; 331 332 /* allocate instance-specific endpoints */ 333 334 ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc); 335 if (!ep) 336 goto fail; 337 obex->port.in = ep; 338 ep->driver_data = cdev; /* claim */ 339 340 ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc); 341 if (!ep) 342 goto fail; 343 obex->port.out = ep; 344 ep->driver_data = cdev; /* claim */ 345 346 /* copy descriptors, and track endpoint copies */ 347 f->descriptors = usb_copy_descriptors(fs_function); 348 349 obex->fs.obex_in = usb_find_endpoint(fs_function, 350 f->descriptors, &obex_fs_ep_in_desc); 351 obex->fs.obex_out = usb_find_endpoint(fs_function, 352 f->descriptors, &obex_fs_ep_out_desc); 353 354 /* support all relevant hardware speeds... we expect that when 355 * hardware is dual speed, all bulk-capable endpoints work at 356 * both speeds 357 */ 358 if (gadget_is_dualspeed(c->cdev->gadget)) { 359 360 obex_hs_ep_in_desc.bEndpointAddress = 361 obex_fs_ep_in_desc.bEndpointAddress; 362 obex_hs_ep_out_desc.bEndpointAddress = 363 obex_fs_ep_out_desc.bEndpointAddress; 364 365 /* copy descriptors, and track endpoint copies */ 366 f->hs_descriptors = usb_copy_descriptors(hs_function); 367 368 obex->hs.obex_in = usb_find_endpoint(hs_function, 369 f->hs_descriptors, &obex_hs_ep_in_desc); 370 obex->hs.obex_out = usb_find_endpoint(hs_function, 371 f->hs_descriptors, &obex_hs_ep_out_desc); 372 } 373 374 /* Avoid letting this gadget enumerate until the userspace 375 * OBEX server is active. 376 */ 377 status = usb_function_deactivate(f); 378 if (status < 0) 379 WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n", 380 obex->port_num, status); 381 else 382 obex->can_activate = true; 383 384 385 DBG(cdev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n", 386 obex->port_num, 387 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", 388 obex->port.in->name, obex->port.out->name); 389 390 return 0; 391 392fail: 393 /* we might as well release our claims on endpoints */ 394 if (obex->port.out) 395 obex->port.out->driver_data = NULL; 396 if (obex->port.in) 397 obex->port.in->driver_data = NULL; 398 399 ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); 400 401 return status; 402} 403 404static void 405obex_unbind(struct usb_configuration *c, struct usb_function *f) 406{ 407 if (gadget_is_dualspeed(c->cdev->gadget)) 408 usb_free_descriptors(f->hs_descriptors); 409 usb_free_descriptors(f->descriptors); 410 kfree(func_to_obex(f)); 411} 412 413/* Some controllers can't support CDC OBEX ... */ 414static inline bool can_support_obex(struct usb_configuration *c) 415{ 416 /* Since the first interface is a NOP, we can ignore the 417 * issue of multi-interface support on most controllers. 418 * 419 * Altsettings are mandatory, however... 420 */ 421 if (!gadget_supports_altsettings(c->cdev->gadget)) 422 return false; 423 424 /* everything else is *probably* fine ... */ 425 return true; 426} 427 428/** 429 * obex_bind_config - add a CDC OBEX function to a configuration 430 * @c: the configuration to support the CDC OBEX instance 431 * @port_num: /dev/ttyGS* port this interface will use 432 * Context: single threaded during gadget setup 433 * 434 * Returns zero on success, else negative errno. 435 * 436 * Caller must have called @gserial_setup() with enough ports to 437 * handle all the ones it binds. Caller is also responsible 438 * for calling @gserial_cleanup() before module unload. 439 */ 440int __init obex_bind_config(struct usb_configuration *c, u8 port_num) 441{ 442 struct f_obex *obex; 443 int status; 444 445 if (!can_support_obex(c)) 446 return -EINVAL; 447 448 /* maybe allocate device-global string IDs, and patch descriptors */ 449 if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { 450 status = usb_string_id(c->cdev); 451 if (status < 0) 452 return status; 453 obex_string_defs[OBEX_CTRL_IDX].id = status; 454 455 obex_control_intf.iInterface = status; 456 457 status = usb_string_id(c->cdev); 458 if (status < 0) 459 return status; 460 obex_string_defs[OBEX_DATA_IDX].id = status; 461 462 obex_data_nop_intf.iInterface = 463 obex_data_intf.iInterface = status; 464 } 465 466 /* allocate and initialize one new instance */ 467 obex = kzalloc(sizeof *obex, GFP_KERNEL); 468 if (!obex) 469 return -ENOMEM; 470 471 obex->port_num = port_num; 472 473 obex->port.connect = obex_connect; 474 obex->port.disconnect = obex_disconnect; 475 476 obex->port.func.name = "obex"; 477 obex->port.func.strings = obex_strings; 478 /* descriptors are per-instance copies */ 479 obex->port.func.bind = obex_bind; 480 obex->port.func.unbind = obex_unbind; 481 obex->port.func.set_alt = obex_set_alt; 482 obex->port.func.get_alt = obex_get_alt; 483 obex->port.func.disable = obex_disable; 484 485 status = usb_add_function(c, &obex->port.func); 486 if (status) 487 kfree(obex); 488 489 return status; 490} 491 492MODULE_AUTHOR("Felipe Balbi"); 493MODULE_LICENSE("GPL");