lkml.org 
[lkml]   [2016]   [Feb]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 24/43] usb: gadget: f_rndis: conversion to new API
    Date
    Generate descriptors in new format and attach them to USB function in
    prep_descs(). Implement prep_vendor_descs() to supply class specific
    descriptors. Change set_alt() implementation and implement clear_alt()
    operation. Remove boilerplate code. Change USB request lifetime
    management - now it's allocated in set_alt() and freed in clear_alt().

    Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
    ---
    drivers/usb/gadget/function/f_rndis.c | 321 ++++++++++++----------------------
    1 file changed, 112 insertions(+), 209 deletions(-)

    diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
    index e587767..abe11a7 100644
    --- a/drivers/usb/gadget/function/f_rndis.c
    +++ b/drivers/usb/gadget/function/f_rndis.c
    @@ -212,24 +212,6 @@ static struct usb_endpoint_descriptor fs_out_desc = {
    .bmAttributes = USB_ENDPOINT_XFER_BULK,
    };

    -static struct usb_descriptor_header *eth_fs_function[] = {
    - (struct usb_descriptor_header *) &rndis_iad_descriptor,
    -
    - /* control interface matches ACM, not Ethernet */
    - (struct usb_descriptor_header *) &rndis_control_intf,
    - (struct usb_descriptor_header *) &header_desc,
    - (struct usb_descriptor_header *) &call_mgmt_descriptor,
    - (struct usb_descriptor_header *) &rndis_acm_descriptor,
    - (struct usb_descriptor_header *) &rndis_union_desc,
    - (struct usb_descriptor_header *) &fs_notify_desc,
    -
    - /* data interface has no altsetting */
    - (struct usb_descriptor_header *) &rndis_data_intf,
    - (struct usb_descriptor_header *) &fs_in_desc,
    - (struct usb_descriptor_header *) &fs_out_desc,
    - NULL,
    -};
    -
    /* high speed support: */

    static struct usb_endpoint_descriptor hs_notify_desc = {
    @@ -260,24 +242,6 @@ static struct usb_endpoint_descriptor hs_out_desc = {
    .wMaxPacketSize = cpu_to_le16(512),
    };

    -static struct usb_descriptor_header *eth_hs_function[] = {
    - (struct usb_descriptor_header *) &rndis_iad_descriptor,
    -
    - /* control interface matches ACM, not Ethernet */
    - (struct usb_descriptor_header *) &rndis_control_intf,
    - (struct usb_descriptor_header *) &header_desc,
    - (struct usb_descriptor_header *) &call_mgmt_descriptor,
    - (struct usb_descriptor_header *) &rndis_acm_descriptor,
    - (struct usb_descriptor_header *) &rndis_union_desc,
    - (struct usb_descriptor_header *) &hs_notify_desc,
    -
    - /* data interface has no altsetting */
    - (struct usb_descriptor_header *) &rndis_data_intf,
    - (struct usb_descriptor_header *) &hs_in_desc,
    - (struct usb_descriptor_header *) &hs_out_desc,
    - NULL,
    -};
    -
    /* super speed support: */

    static struct usb_endpoint_descriptor ss_notify_desc = {
    @@ -327,26 +291,20 @@ static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
    /* .bmAttributes = 0, */
    };

    -static struct usb_descriptor_header *eth_ss_function[] = {
    - (struct usb_descriptor_header *) &rndis_iad_descriptor,
    -
    - /* control interface matches ACM, not Ethernet */
    - (struct usb_descriptor_header *) &rndis_control_intf,
    - (struct usb_descriptor_header *) &header_desc,
    - (struct usb_descriptor_header *) &call_mgmt_descriptor,
    - (struct usb_descriptor_header *) &rndis_acm_descriptor,
    - (struct usb_descriptor_header *) &rndis_union_desc,
    - (struct usb_descriptor_header *) &ss_notify_desc,
    - (struct usb_descriptor_header *) &ss_intr_comp_desc,
    -
    - /* data interface has no altsetting */
    - (struct usb_descriptor_header *) &rndis_data_intf,
    - (struct usb_descriptor_header *) &ss_in_desc,
    - (struct usb_descriptor_header *) &ss_bulk_comp_desc,
    - (struct usb_descriptor_header *) &ss_out_desc,
    - (struct usb_descriptor_header *) &ss_bulk_comp_desc,
    - NULL,
    -};
    +USB_COMPOSITE_ENDPOINT(ep_notify, &fs_notify_desc, &hs_notify_desc,
    + &ss_notify_desc, &ss_intr_comp_desc);
    +USB_COMPOSITE_ENDPOINT(ep_in, &fs_in_desc, &hs_in_desc,
    + &ss_in_desc, &ss_bulk_comp_desc);
    +USB_COMPOSITE_ENDPOINT(ep_out, &fs_out_desc, &hs_out_desc,
    + &ss_out_desc, &ss_bulk_comp_desc);
    +
    +USB_COMPOSITE_ALTSETTING(intf0alt0, &rndis_control_intf, &ep_notify);
    +USB_COMPOSITE_ALTSETTING(intf1alt0, &rndis_data_intf, &ep_in, &ep_out);
    +
    +USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
    +USB_COMPOSITE_INTERFACE(intf1, &intf1alt0);
    +
    +USB_COMPOSITE_DESCRIPTORS(rndis_descs, &intf0, &intf1);

    /* string descriptors: */

    @@ -542,36 +500,35 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)

    /* we know alt == 0 */

    - if (intf == rndis->ctrl_id) {
    + if (intf == 0) {
    VDBG(cdev, "reset rndis control %d\n", intf);
    - usb_ep_disable(rndis->notify);

    - if (!rndis->notify->desc) {
    - VDBG(cdev, "init rndis ctrl %d\n", intf);
    - if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
    - goto fail;
    - }
    - usb_ep_enable(rndis->notify);
    -
    - } else if (intf == rndis->data_id) {
    - struct net_device *net;
    + rndis->notify = usb_function_get_ep(f, intf, 0);
    + if (!rndis->notify)
    + return -ENODEV;

    - if (rndis->port.in_ep->enabled) {
    - DBG(cdev, "reset rndis\n");
    - gether_disconnect(&rndis->port);
    + /* allocate notification request and buffer */
    + rndis->notify_req = usb_ep_alloc_request(rndis->notify,
    + GFP_KERNEL);
    + if (!rndis->notify_req)
    + return -ENOMEM;
    + rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
    + if (!rndis->notify_req->buf) {
    + usb_ep_free_request(rndis->notify, rndis->notify_req);
    + return -ENOMEM;
    }
    + rndis->notify_req->length = STATUS_BYTECOUNT;
    + rndis->notify_req->context = rndis;
    + rndis->notify_req->complete = rndis_response_complete;
    + } else if (intf == 1) {
    + struct net_device *net;

    - if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
    - DBG(cdev, "init rndis\n");
    - if (config_ep_by_speed(cdev->gadget, f,
    - rndis->port.in_ep) ||
    - config_ep_by_speed(cdev->gadget, f,
    - rndis->port.out_ep)) {
    - rndis->port.in_ep->desc = NULL;
    - rndis->port.out_ep->desc = NULL;
    - goto fail;
    - }
    - }
    + rndis->port.in_ep = usb_function_get_ep(f, intf, 0);
    + if (!rndis->port.in_ep)
    + return -ENODEV;
    + rndis->port.out_ep = usb_function_get_ep(f, intf, 1);
    + if (!rndis->port.out_ep)
    + return -ENODEV;

    /* Avoid ZLPs; they can be troublesome. */
    rndis->port.is_zlp_ok = false;
    @@ -597,28 +554,25 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)

    rndis_set_param_dev(rndis->params, net,
    &rndis->port.cdc_filter);
    - } else
    - goto fail;
    + }

    return 0;
    -fail:
    - return -EINVAL;
    }

    -static void rndis_disable(struct usb_function *f)
    +static void rndis_clear_alt(struct usb_function *f,
    + unsigned intf, unsigned alt)
    {
    struct f_rndis *rndis = func_to_rndis(f);
    struct usb_composite_dev *cdev = f->config->cdev;

    - if (!rndis->notify->enabled)
    - return;
    -
    - DBG(cdev, "rndis deactivated\n");
    -
    - rndis_uninit(rndis->params);
    - gether_disconnect(&rndis->port);
    -
    - usb_ep_disable(rndis->notify);
    + if (intf == 0) {
    + kfree(rndis->notify_req->buf);
    + usb_ep_free_request(rndis->notify, rndis->notify_req);
    + } else if (intf == 1) {
    + DBG(cdev, "rndis deactivated\n");
    + rndis_uninit(rndis->params);
    + gether_disconnect(&rndis->port);
    + }
    }

    /*-------------------------------------------------------------------------*/
    @@ -663,22 +617,19 @@ static inline bool can_support_rndis(struct usb_configuration *c)

    /* ethernet function driver setup/binding */

    -static int
    -rndis_bind(struct usb_configuration *c, struct usb_function *f)
    +static int rndis_prep_descs(struct usb_function *f)
    {
    - struct usb_composite_dev *cdev = c->cdev;
    struct f_rndis *rndis = func_to_rndis(f);
    - struct usb_string *us;
    + struct f_rndis_opts *rndis_opts;
    + struct usb_composite_dev *cdev = f->config->cdev;
    + struct usb_string *us;
    int status;
    - struct usb_ep *ep;

    - struct f_rndis_opts *rndis_opts;
    + rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);

    - if (!can_support_rndis(c))
    + if (!can_support_rndis(f->config))
    return -EINVAL;

    - rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
    -
    if (cdev->use_os_string) {
    f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
    GFP_KERNEL);
    @@ -688,21 +639,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
    f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
    }

    - /*
    - * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
    - * configurations are bound in sequence with list_for_each_entry,
    - * in each configuration its functions are bound in sequence
    - * with list_for_each_entry, so we assume no race condition
    - * with regard to rndis_opts->bound access
    - */
    - if (!rndis_opts->bound) {
    - gether_set_gadget(rndis_opts->net, cdev->gadget);
    - status = gether_register_netdev(rndis_opts->net);
    - if (status)
    - goto fail;
    - rndis_opts->bound = true;
    - }
    -
    us = usb_gstrings_attach(cdev, rndis_strings,
    ARRAY_SIZE(rndis_string_defs));
    if (IS_ERR(us)) {
    @@ -713,79 +649,72 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
    rndis_data_intf.iInterface = us[1].id;
    rndis_iad_descriptor.iFunction = us[2].id;

    - /* allocate instance-specific interface IDs */
    - status = usb_interface_id(c, f);
    - if (status < 0)
    - goto fail;
    - rndis->ctrl_id = status;
    - rndis_iad_descriptor.bFirstInterface = status;
    -
    - rndis_control_intf.bInterfaceNumber = status;
    - rndis_union_desc.bMasterInterface0 = status;
    + return usb_function_set_descs(f, &rndis_descs);

    - if (cdev->use_os_string)
    - f->os_desc_table[0].if_id =
    - rndis_iad_descriptor.bFirstInterface;
    +fail:
    + kfree(f->os_desc_table);
    + f->os_desc_n = 0;

    - status = usb_interface_id(c, f);
    - if (status < 0)
    - goto fail;
    - rndis->data_id = status;
    + if (rndis->notify_req) {
    + kfree(rndis->notify_req->buf);
    + usb_ep_free_request(rndis->notify, rndis->notify_req);
    + }

    - rndis_data_intf.bInterfaceNumber = status;
    - rndis_union_desc.bSlaveInterface0 = status;
    + ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

    - status = -ENODEV;
    + return status;
    +}

    - /* allocate instance-specific endpoints */
    - ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
    - if (!ep)
    - goto fail;
    - rndis->port.in_ep = ep;
    +static int rndis_prep_vendor_descs(struct usb_function *f)
    +{
    + struct f_rndis *rndis = func_to_rndis(f);
    + struct f_rndis_opts *rndis_opts;
    + struct usb_composite_dev *cdev = f->config->cdev;
    + int status, intf0_id, intf1_id;

    - ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
    - if (!ep)
    - goto fail;
    - rndis->port.out_ep = ep;
    + rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);

    - /* NOTE: a status/notification endpoint is, strictly speaking,
    - * optional. We don't treat it that way though! It's simpler,
    - * and some newer profiles don't treat it as optional.
    + /*
    + * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
    + * configurations are bound in sequence with list_for_each_entry,
    + * in each configuration its functions are bound in sequence
    + * with list_for_each_entry, so we assume no race condition
    + * with regard to rndis_opts->bound access
    */
    - ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
    - if (!ep)
    - goto fail;
    - rndis->notify = ep;
    + if (!rndis_opts->bound) {
    + gether_set_gadget(rndis_opts->net, cdev->gadget);
    + status = gether_register_netdev(rndis_opts->net);
    + if (status)
    + return status;
    + rndis_opts->bound = true;
    + }

    - status = -ENOMEM;
    + intf0_id = usb_get_interface_id(f, 0);
    + intf1_id = usb_get_interface_id(f, 1);

    - /* allocate notification request and buffer */
    - rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
    - if (!rndis->notify_req)
    - goto fail;
    - rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
    - if (!rndis->notify_req->buf)
    - goto fail;
    - rndis->notify_req->length = STATUS_BYTECOUNT;
    - rndis->notify_req->context = rndis;
    - rndis->notify_req->complete = rndis_response_complete;
    + rndis->ctrl_id = intf0_id;
    + rndis->data_id = intf1_id;

    - /* support all relevant hardware speeds... we expect that when
    - * hardware is dual speed, all bulk-capable endpoints work at
    - * both speeds
    - */
    - hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
    - hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
    - hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
    + rndis_iad_descriptor.bFirstInterface = intf0_id;

    - ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
    - ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
    - ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
    + rndis_union_desc.bMasterInterface0 = intf0_id;
    + rndis_union_desc.bSlaveInterface0 = intf1_id;

    - status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
    - eth_ss_function);
    - if (status)
    - goto fail;
    + if (cdev->use_os_string)
    + f->os_desc_table[0].if_id =
    + rndis_iad_descriptor.bFirstInterface;
    +
    + usb_function_add_vendor_desc(f,
    + (struct usb_descriptor_header *)&rndis_iad_descriptor);
    +
    + usb_altset_add_vendor_desc(f, 0, 0,
    + (struct usb_descriptor_header *)&header_desc);
    + usb_altset_add_vendor_desc(f, 0, 0,
    + (struct usb_descriptor_header *)&call_mgmt_descriptor);
    + usb_altset_add_vendor_desc(f, 0, 0,
    + (struct usb_descriptor_header *)&rndis_acm_descriptor);
    + usb_altset_add_vendor_desc(f, 0, 0,
    + (struct usb_descriptor_header *)&rndis_union_desc);

    rndis->port.open = rndis_open;
    rndis->port.close = rndis_close;
    @@ -796,8 +725,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
    if (rndis->manufacturer && rndis->vendorID &&
    rndis_set_param_vendor(rndis->params, rndis->vendorID,
    rndis->manufacturer)) {
    - status = -EINVAL;
    - goto fail_free_descs;
    + return -EINVAL;
    }

    /* NOTE: all that is done without knowing or caring about
    @@ -805,27 +733,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
    * until we're activated via set_alt().
    */

    - DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
    - gadget_is_superspeed(c->cdev->gadget) ? "super" :
    - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
    - rndis->port.in_ep->name, rndis->port.out_ep->name,
    - rndis->notify->name);
    return 0;
    -
    -fail_free_descs:
    - usb_free_all_descriptors(f);
    -fail:
    - kfree(f->os_desc_table);
    - f->os_desc_n = 0;
    -
    - if (rndis->notify_req) {
    - kfree(rndis->notify_req->buf);
    - usb_ep_free_request(rndis->notify, rndis->notify_req);
    - }
    -
    - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
    -
    - return status;
    }

    void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
    @@ -940,14 +848,8 @@ static void rndis_free(struct usb_function *f)

    static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
    {
    - struct f_rndis *rndis = func_to_rndis(f);
    -
    kfree(f->os_desc_table);
    f->os_desc_n = 0;
    - usb_free_all_descriptors(f);
    -
    - kfree(rndis->notify_req->buf);
    - usb_ep_free_request(rndis->notify, rndis->notify_req);
    }

    static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
    @@ -981,11 +883,12 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)

    rndis->port.func.name = "rndis";
    /* descriptors are per-instance copies */
    - rndis->port.func.bind = rndis_bind;
    + rndis->port.func.prep_descs = rndis_prep_descs;
    + rndis->port.func.prep_vendor_descs = rndis_prep_vendor_descs;
    rndis->port.func.unbind = rndis_unbind;
    rndis->port.func.set_alt = rndis_set_alt;
    + rndis->port.func.clear_alt = rndis_clear_alt;
    rndis->port.func.setup = rndis_setup;
    - rndis->port.func.disable = rndis_disable;
    rndis->port.func.free_func = rndis_free;

    params = rndis_register(rndis_response_available, rndis);
    --
    1.9.1
    \
     
     \ /
      Last update: 2016-02-03 14:01    [W:4.375 / U:0.336 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site