root/drivers/usb/gadget/function/f_obex.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. func_to_obex
  2. port_to_obex
  3. obex_set_alt
  4. obex_get_alt
  5. obex_disable
  6. obex_connect
  7. obex_disconnect
  8. can_support_obex
  9. obex_bind
  10. to_f_serial_opts
  11. obex_attr_release
  12. f_obex_port_num_show
  13. obex_free_inst
  14. obex_alloc_inst
  15. obex_free
  16. obex_unbind
  17. obex_alloc

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

/* [<][>][^][v][top][bottom][index][help] */