linux/drivers/usb/gadget/g_ffs.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/utsname.h>
   3
   4
   5/*
   6 * kbuild is not very cooperative with respect to linking separately
   7 * compiled library objects into one module.  So for now we won't use
   8 * separate compilation ... ensuring init/exit sections work to shrink
   9 * the runtime footprint, and giving us at least some parts of what
  10 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  11 */
  12
  13#include "composite.c"
  14#include "usbstring.c"
  15#include "config.c"
  16#include "epautoconf.c"
  17
  18#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
  19#  if defined USB_ETH_RNDIS
  20#    undef USB_ETH_RNDIS
  21#  endif
  22#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
  23#    define USB_ETH_RNDIS y
  24#  endif
  25
  26#  include "f_ecm.c"
  27#  include "f_subset.c"
  28#  ifdef USB_ETH_RNDIS
  29#    include "f_rndis.c"
  30#    include "rndis.c"
  31#  endif
  32#  include "u_ether.c"
  33
  34static u8 gfs_hostaddr[ETH_ALEN];
  35#else
  36#  if !defined CONFIG_USB_FUNCTIONFS_GENERIC
  37#    define CONFIG_USB_FUNCTIONFS_GENERIC
  38#  endif
  39#  define gether_cleanup() do { } while (0)
  40#  define gether_setup(gadget, hostaddr)   ((int)0)
  41#endif
  42
  43#include "f_fs.c"
  44
  45
  46#define DRIVER_NAME     "g_ffs"
  47#define DRIVER_DESC     "USB Function Filesystem"
  48#define DRIVER_VERSION  "24 Aug 2004"
  49
  50MODULE_DESCRIPTION(DRIVER_DESC);
  51MODULE_AUTHOR("Michal Nazarewicz");
  52MODULE_LICENSE("GPL");
  53
  54
  55static unsigned short gfs_vendor_id    = 0x0525;        /* XXX NetChip */
  56static unsigned short gfs_product_id   = 0xa4ac;        /* XXX */
  57
  58static struct usb_device_descriptor gfs_dev_desc = {
  59        .bLength                = sizeof gfs_dev_desc,
  60        .bDescriptorType        = USB_DT_DEVICE,
  61
  62        .bcdUSB                 = cpu_to_le16(0x0200),
  63        .bDeviceClass           = USB_CLASS_PER_INTERFACE,
  64
  65        /* Vendor and product id can be overridden by module parameters.  */
  66        /* .idVendor            = cpu_to_le16(gfs_vendor_id), */
  67        /* .idProduct           = cpu_to_le16(gfs_product_id), */
  68        /* .bcdDevice           = f(hardware) */
  69        /* .iManufacturer       = DYNAMIC */
  70        /* .iProduct            = DYNAMIC */
  71        /* NO SERIAL NUMBER */
  72        .bNumConfigurations     = 1,
  73};
  74
  75#define GFS_MODULE_PARAM_DESC(name, field) \
  76        MODULE_PARM_DESC(name, "Value of the " #field " field of the device descriptor sent to the host.  Takes effect only prior to the user-space driver registering to the FunctionFS.")
  77
  78module_param_named(usb_class,    gfs_dev_desc.bDeviceClass,    byte,   0644);
  79GFS_MODULE_PARAM_DESC(usb_class, bDeviceClass);
  80module_param_named(usb_subclass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
  81GFS_MODULE_PARAM_DESC(usb_subclass, bDeviceSubClass);
  82module_param_named(usb_protocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
  83GFS_MODULE_PARAM_DESC(usb_protocol, bDeviceProtocol);
  84module_param_named(usb_vendor,   gfs_vendor_id,                ushort, 0644);
  85GFS_MODULE_PARAM_DESC(usb_vendor, idVendor);
  86module_param_named(usb_product,  gfs_product_id,               ushort, 0644);
  87GFS_MODULE_PARAM_DESC(usb_product, idProduct);
  88
  89
  90
  91static const struct usb_descriptor_header *gfs_otg_desc[] = {
  92        (const struct usb_descriptor_header *)
  93        &(const struct usb_otg_descriptor) {
  94                .bLength                = sizeof(struct usb_otg_descriptor),
  95                .bDescriptorType        = USB_DT_OTG,
  96
  97                /* REVISIT SRP-only hardware is possible, although
  98                 * it would not be called "OTG" ... */
  99                .bmAttributes           = USB_OTG_SRP | USB_OTG_HNP,
 100        },
 101
 102        NULL
 103};
 104
 105/* string IDs are assigned dynamically */
 106
 107enum {
 108        GFS_STRING_MANUFACTURER_IDX,
 109        GFS_STRING_PRODUCT_IDX,
 110#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 111        GFS_STRING_RNDIS_CONFIG_IDX,
 112#endif
 113#ifdef CONFIG_USB_FUNCTIONFS_ETH
 114        GFS_STRING_ECM_CONFIG_IDX,
 115#endif
 116#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 117        GFS_STRING_GENERIC_CONFIG_IDX,
 118#endif
 119};
 120
 121static       char gfs_manufacturer[50];
 122static const char gfs_driver_desc[] = DRIVER_DESC;
 123static const char gfs_short_name[]  = DRIVER_NAME;
 124
 125static struct usb_string gfs_strings[] = {
 126        [GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
 127        [GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
 128#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 129        [GFS_STRING_RNDIS_CONFIG_IDX].s = "FunctionFS + RNDIS",
 130#endif
 131#ifdef CONFIG_USB_FUNCTIONFS_ETH
 132        [GFS_STRING_ECM_CONFIG_IDX].s = "FunctionFS + ECM",
 133#endif
 134#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 135        [GFS_STRING_GENERIC_CONFIG_IDX].s = "FunctionFS",
 136#endif
 137        {  } /* end of list */
 138};
 139
 140static struct usb_gadget_strings *gfs_dev_strings[] = {
 141        &(struct usb_gadget_strings) {
 142                .language       = 0x0409,       /* en-us */
 143                .strings        = gfs_strings,
 144        },
 145        NULL,
 146};
 147
 148
 149#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 150static int gfs_do_rndis_config(struct usb_configuration *c);
 151
 152static struct usb_configuration gfs_rndis_config_driver = {
 153        .label                  = "FunctionFS + RNDIS",
 154        .bind                   = gfs_do_rndis_config,
 155        .bConfigurationValue    = 1,
 156        /* .iConfiguration      = DYNAMIC */
 157        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 158};
 159#  define gfs_add_rndis_config(cdev) \
 160        usb_add_config(cdev, &gfs_rndis_config_driver)
 161#else
 162#  define gfs_add_rndis_config(cdev) 0
 163#endif
 164
 165
 166#ifdef CONFIG_USB_FUNCTIONFS_ETH
 167static int gfs_do_ecm_config(struct usb_configuration *c);
 168
 169static struct usb_configuration gfs_ecm_config_driver = {
 170        .label                  = "FunctionFS + ECM",
 171        .bind                   = gfs_do_ecm_config,
 172        .bConfigurationValue    = 1,
 173        /* .iConfiguration      = DYNAMIC */
 174        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 175};
 176#  define gfs_add_ecm_config(cdev) \
 177        usb_add_config(cdev, &gfs_ecm_config_driver)
 178#else
 179#  define gfs_add_ecm_config(cdev) 0
 180#endif
 181
 182
 183#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 184static int gfs_do_generic_config(struct usb_configuration *c);
 185
 186static struct usb_configuration gfs_generic_config_driver = {
 187        .label                  = "FunctionFS",
 188        .bind                   = gfs_do_generic_config,
 189        .bConfigurationValue    = 2,
 190        /* .iConfiguration      = DYNAMIC */
 191        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 192};
 193#  define gfs_add_generic_config(cdev) \
 194        usb_add_config(cdev, &gfs_generic_config_driver)
 195#else
 196#  define gfs_add_generic_config(cdev) 0
 197#endif
 198
 199
 200static int gfs_bind(struct usb_composite_dev *cdev);
 201static int gfs_unbind(struct usb_composite_dev *cdev);
 202
 203static struct usb_composite_driver gfs_driver = {
 204        .name           = gfs_short_name,
 205        .dev            = &gfs_dev_desc,
 206        .strings        = gfs_dev_strings,
 207        .bind           = gfs_bind,
 208        .unbind         = gfs_unbind,
 209};
 210
 211
 212static struct ffs_data *gfs_ffs_data;
 213static unsigned long gfs_registered;
 214
 215
 216static int  gfs_init(void)
 217{
 218        ENTER();
 219
 220        return functionfs_init();
 221}
 222module_init(gfs_init);
 223
 224static void  gfs_exit(void)
 225{
 226        ENTER();
 227
 228        if (test_and_clear_bit(0, &gfs_registered))
 229                usb_composite_unregister(&gfs_driver);
 230
 231        functionfs_cleanup();
 232}
 233module_exit(gfs_exit);
 234
 235
 236static int functionfs_ready_callback(struct ffs_data *ffs)
 237{
 238        int ret;
 239
 240        ENTER();
 241
 242        if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
 243                return -EBUSY;
 244
 245        gfs_ffs_data = ffs;
 246        ret = usb_composite_register(&gfs_driver);
 247        if (unlikely(ret < 0))
 248                clear_bit(0, &gfs_registered);
 249        return ret;
 250}
 251
 252static void functionfs_closed_callback(struct ffs_data *ffs)
 253{
 254        ENTER();
 255
 256        if (test_and_clear_bit(0, &gfs_registered))
 257                usb_composite_unregister(&gfs_driver);
 258}
 259
 260
 261static int functionfs_check_dev_callback(const char *dev_name)
 262{
 263        return 0;
 264}
 265
 266
 267
 268static int gfs_bind(struct usb_composite_dev *cdev)
 269{
 270        int ret;
 271
 272        ENTER();
 273
 274        if (WARN_ON(!gfs_ffs_data))
 275                return -ENODEV;
 276
 277        ret = gether_setup(cdev->gadget, gfs_hostaddr);
 278        if (unlikely(ret < 0))
 279                goto error_quick;
 280
 281        gfs_dev_desc.idVendor  = cpu_to_le16(gfs_vendor_id);
 282        gfs_dev_desc.idProduct = cpu_to_le16(gfs_product_id);
 283
 284        snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
 285                 init_utsname()->sysname, init_utsname()->release,
 286                 cdev->gadget->name);
 287        ret = usb_string_id(cdev);
 288        if (unlikely(ret < 0))
 289                goto error;
 290        gfs_strings[GFS_STRING_MANUFACTURER_IDX].id = ret;
 291        gfs_dev_desc.iManufacturer = ret;
 292
 293        ret = usb_string_id(cdev);
 294        if (unlikely(ret < 0))
 295                goto error;
 296        gfs_strings[GFS_STRING_PRODUCT_IDX].id = ret;
 297        gfs_dev_desc.iProduct = ret;
 298
 299#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 300        ret = usb_string_id(cdev);
 301        if (unlikely(ret < 0))
 302                goto error;
 303        gfs_strings[GFS_STRING_RNDIS_CONFIG_IDX].id = ret;
 304        gfs_rndis_config_driver.iConfiguration = ret;
 305#endif
 306
 307#ifdef CONFIG_USB_FUNCTIONFS_ETH
 308        ret = usb_string_id(cdev);
 309        if (unlikely(ret < 0))
 310                goto error;
 311        gfs_strings[GFS_STRING_ECM_CONFIG_IDX].id = ret;
 312        gfs_ecm_config_driver.iConfiguration = ret;
 313#endif
 314
 315#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 316        ret = usb_string_id(cdev);
 317        if (unlikely(ret < 0))
 318                goto error;
 319        gfs_strings[GFS_STRING_GENERIC_CONFIG_IDX].id = ret;
 320        gfs_generic_config_driver.iConfiguration = ret;
 321#endif
 322
 323        ret = functionfs_bind(gfs_ffs_data, cdev);
 324        if (unlikely(ret < 0))
 325                goto error;
 326
 327        ret = gfs_add_rndis_config(cdev);
 328        if (unlikely(ret < 0))
 329                goto error_unbind;
 330
 331        ret = gfs_add_ecm_config(cdev);
 332        if (unlikely(ret < 0))
 333                goto error_unbind;
 334
 335        ret = gfs_add_generic_config(cdev);
 336        if (unlikely(ret < 0))
 337                goto error_unbind;
 338
 339        return 0;
 340
 341error_unbind:
 342        functionfs_unbind(gfs_ffs_data);
 343error:
 344        gether_cleanup();
 345error_quick:
 346        gfs_ffs_data = NULL;
 347        return ret;
 348}
 349
 350static int gfs_unbind(struct usb_composite_dev *cdev)
 351{
 352        ENTER();
 353
 354        /* We may have been called in an error recovery frem
 355         * composite_bind() after gfs_unbind() failure so we need to
 356         * check if gfs_ffs_data is not NULL since gfs_bind() handles
 357         * all error recovery itself.  I'd rather we werent called
 358         * from composite on orror recovery, but what you're gonna
 359         * do...? */
 360
 361        if (gfs_ffs_data) {
 362                gether_cleanup();
 363                functionfs_unbind(gfs_ffs_data);
 364                gfs_ffs_data = NULL;
 365        }
 366
 367        return 0;
 368}
 369
 370
 371static int __gfs_do_config(struct usb_configuration *c,
 372                           int (*eth)(struct usb_configuration *c, u8 *ethaddr),
 373                           u8 *ethaddr)
 374{
 375        int ret;
 376
 377        if (WARN_ON(!gfs_ffs_data))
 378                return -ENODEV;
 379
 380        if (gadget_is_otg(c->cdev->gadget)) {
 381                c->descriptors = gfs_otg_desc;
 382                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 383        }
 384
 385        if (eth) {
 386                ret = eth(c, ethaddr);
 387                if (unlikely(ret < 0))
 388                        return ret;
 389        }
 390
 391        ret = functionfs_add(c->cdev, c, gfs_ffs_data);
 392        if (unlikely(ret < 0))
 393                return ret;
 394
 395        /* After previous do_configs there may be some invalid
 396         * pointers in c->interface array.  This happens every time
 397         * a user space function with fewer interfaces than a user
 398         * space function that was run before the new one is run.  The
 399         * compasit's set_config() assumes that if there is no more
 400         * then MAX_CONFIG_INTERFACES interfaces in a configuration
 401         * then there is a NULL pointer after the last interface in
 402         * c->interface array.  We need to make sure this is true. */
 403        if (c->next_interface_id < ARRAY_SIZE(c->interface))
 404                c->interface[c->next_interface_id] = NULL;
 405
 406        return 0;
 407}
 408
 409#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 410static int gfs_do_rndis_config(struct usb_configuration *c)
 411{
 412        ENTER();
 413
 414        return __gfs_do_config(c, rndis_bind_config, gfs_hostaddr);
 415}
 416#endif
 417
 418#ifdef CONFIG_USB_FUNCTIONFS_ETH
 419static int gfs_do_ecm_config(struct usb_configuration *c)
 420{
 421        ENTER();
 422
 423        return __gfs_do_config(c,
 424                               can_support_ecm(c->cdev->gadget)
 425                             ? ecm_bind_config : geth_bind_config,
 426                               gfs_hostaddr);
 427}
 428#endif
 429
 430#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 431static int gfs_do_generic_config(struct usb_configuration *c)
 432{
 433        ENTER();
 434
 435        return __gfs_do_config(c, NULL, NULL);
 436}
 437#endif
 438
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.