From: Ragner Magalhaes <[EMAIL PROTECTED]>

This patch adds some features that let the file-storage gadget
to work as a usb_function module.

Signed-off-by: Felipe Balbi <[EMAIL PROTECTED]>
Signed-off-by: Ragner Magalhaes <[EMAIL PROTECTED]>
---

 drivers/usb/gadget/file_storage.c |  119 ++++++++++++++++---------------------
 1 files changed, 51 insertions(+), 68 deletions(-)

diff --git a/drivers/usb/gadget/file_storage.c 
b/drivers/usb/gadget/file_storage.c
index c6b6479..fcaf3b3 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -255,6 +255,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
+#include <linux/usb/composite.h>
 
 #include "gadget_chips.h"
 
@@ -640,6 +641,7 @@ struct fsg_dev {
        /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
        spinlock_t              lock;
        struct usb_gadget       *gadget;
+       struct usb_function     *f;
 
        /* filesem protects: backing files in use */
        struct rw_semaphore     filesem;
@@ -732,7 +734,7 @@ static void inline set_bulk_out_req_length(struct fsg_dev 
*fsg,
 }
 
 static struct fsg_dev                  *the_fsg;
-static struct usb_gadget_driver                fsg_driver;
+static struct usb_function             fsg_driver;
 
 static void    close_backing_file(struct lun *curlun);
 static void    close_all_backing_files(struct fsg_dev *fsg);
@@ -848,7 +850,8 @@ static void inline put_be32(u8 *buf, u32 val)
 #define STRING_PRODUCT         2
 #define STRING_SERIAL          3
 #define STRING_CONFIG          4
-#define STRING_INTERFACE       5
+
+#define STRING_INTERFACE       6
 
 /* There is only one configuration. */
 #define        CONFIG_VALUE            1
@@ -1052,9 +1055,10 @@ static struct usb_gadget_strings stringtab = {
  * and with code managing interfaces and their altsettings.  They must
  * also handle different speeds and other-speed requests.
  */
-static int populate_config_buf(struct usb_gadget *gadget,
+static int populate_config_buf(struct fsg_dev *dev,
                u8 *buf, u8 type, unsigned index)
 {
+       struct usb_gadget                       *gadget = dev->gadget;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
        enum usb_device_speed                   speed = gadget->speed;
 #endif
@@ -1074,9 +1078,15 @@ static int populate_config_buf(struct usb_gadget *gadget,
                function = fs_function;
 
        /* for now, don't advertise srp-only devices */
-       if (!gadget->is_otg)
+       if (!gadget->is_otg || is_composite())
                function++;
 
+       if (is_composite()) {
+               buf += dev->ep0req->length;
+               len = EP0_BUFSIZE - dev->ep0req->length;
+               return usb_descriptor_fillbuf(buf, len, function);
+       }
+
        len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
        ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
        return len;
@@ -1125,7 +1135,7 @@ static void raise_exception(struct fsg_dev *fsg, enum 
fsg_state new_state)
 
 static void fsg_disconnect(struct usb_gadget *gadget)
 {
-       struct fsg_dev          *fsg = get_gadget_data(gadget);
+       struct fsg_dev          *fsg = get_usb_function_data(gadget);
 
        DBG(fsg, "disconnect or port reset\n");
        raise_exception(fsg, FSG_STATE_DISCONNECT);
@@ -1415,10 +1425,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                get_config:
 #endif
-                       value = populate_config_buf(fsg->gadget,
-                                       req->buf,
-                                       w_value >> 8,
-                                       w_value & 0xff);
+                       value = populate_config_buf(fsg, req->buf,
+                                       w_value >> 8, w_value & 0xff);
                        break;
 
                case USB_DT_STRING:
@@ -1479,7 +1487,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        break;
                }
                VDBG(fsg, "get interface\n");
-               *(u8 *) req->buf = 0;
+               *(u8 *) req->buf = INTRF_FUNC2COMPOSITE(fsg->f,0);
                value = 1;
                break;
 
@@ -1497,13 +1505,16 @@ static int standard_setup_req(struct fsg_dev *fsg,
 static int fsg_setup(struct usb_gadget *gadget,
                const struct usb_ctrlrequest *ctrl)
 {
-       struct fsg_dev          *fsg = get_gadget_data(gadget);
+       struct fsg_dev          *fsg = get_usb_function_data(gadget);
        int                     rc;
-       int                     w_length = le16_to_cpu(ctrl->wLength);
 
        ++fsg->ep0_req_tag;             // Record arrival of a new request
        fsg->ep0req->context = NULL;
-       fsg->ep0req->length = 0;
+       if (is_composite()) {
+               fsg->ep0req->complete = ep0_complete;
+               gadget->ep0->driver_data = fsg;
+       }
+
        dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
 
        if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
@@ -1511,16 +1522,6 @@ static int fsg_setup(struct usb_gadget *gadget,
        else
                rc = standard_setup_req(fsg, ctrl);
 
-       /* Respond with data/status or defer until later? */
-       if (rc >= 0 && rc != DELAYED_STATUS) {
-               rc = min(rc, w_length);
-               fsg->ep0req->length = rc;
-               fsg->ep0req->zero = rc < w_length;
-               fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
-                               "ep0-in" : "ep0-out");
-               rc = ep0_queue(fsg);
-       }
-
        /* Device either stalls (rc < 0) or reports success */
        return rc;
 }
@@ -3399,7 +3400,8 @@ static void handle_exception(struct fsg_dev *fsg)
 
        case FSG_STATE_CONFIG_CHANGE:
                rc = do_set_config(fsg, new_config);
-               if (fsg->ep0_req_tag != exception_req_tag)
+               if (fsg->ep0_req_tag != exception_req_tag
+                               || is_composite())
                        break;
                if (rc != 0)                    // STALL on errors
                        fsg_set_halt(fsg, fsg->ep0);
@@ -3485,7 +3487,7 @@ static int fsg_main_thread(void *fsg_)
        /* In case we are exiting because of a signal, unregister the
         * gadget driver and close the backing file. */
        if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) {
-               usb_gadget_unregister_driver(&fsg_driver);
+               usb_func_unregister(&fsg_driver);
                close_all_backing_files(fsg);
        }
 
@@ -3704,14 +3706,18 @@ static void lun_release(struct device *dev)
        kref_put(&fsg->ref, fsg_release);
 }
 
+
 static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 {
-       struct fsg_dev          *fsg = get_gadget_data(gadget);
+       struct fsg_dev          *fsg = get_usb_function_data(gadget);
        int                     i;
        struct lun              *curlun;
-       struct usb_request      *req = fsg->ep0req;
 
        DBG(fsg, "unbind\n");
+
+       if (is_composite())
+               do_set_interface(fsg, -1);
+
        clear_bit(REGISTERED, &fsg->atomic_bitflags);
 
        /* Unregister the sysfs attribute files and the LUNs */
@@ -3742,16 +3748,6 @@ static void /* __init_or_exit */ fsg_unbind(struct 
usb_gadget *gadget)
                        usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
                                        mod_data.buflen);
        }
-
-       /* Free the request and buffer for endpoint 0 */
-       if (req) {
-               if (req->buf)
-                       usb_ep_free_buffer(fsg->ep0, req->buf,
-                                       req->dma, EP0_BUFSIZE);
-               usb_ep_free_request(fsg->ep0, req);
-       }
-
-       set_gadget_data(gadget, NULL);
 }
 
 
@@ -3851,7 +3847,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        char                    *pathbuf, *p;
 
        fsg->gadget = gadget;
-       set_gadget_data(gadget, fsg);
+       fsg->f = get_usb_function(gadget);
+       set_usb_function_data(fsg->f, fsg);
        fsg->ep0 = gadget->ep0;
        fsg->ep0->driver_data = fsg;
 
@@ -3888,7 +3885,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
                curlun->ro = mod_data.ro[i];
                curlun->dev.release = lun_release;
                curlun->dev.parent = &gadget->dev;
-               curlun->dev.driver = &fsg_driver.driver;
+               curlun->dev.driver = gadget->dev.driver;
                dev_set_drvdata(&curlun->dev, fsg);
                snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
                                "%s-lun%d", gadget->dev.bus_id, i);
@@ -3919,7 +3916,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        }
 
        /* Find all the endpoints we will use */
-       usb_ep_autoconfig_reset(gadget);
        ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
        if (!ep)
                goto autoconf_fail;
@@ -3972,13 +3968,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        rc = -ENOMEM;
 
        /* Allocate the request and buffer for endpoint 0 */
-       fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
-       if (!req)
-               goto out;
-       req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
-                       &req->dma, GFP_KERNEL);
-       if (!req->buf)
-               goto out;
+       fsg->ep0req = req = get_usb_gadget_request(gadget);
        req->complete = ep0_complete;
 
        /* Allocate the data buffers */
@@ -4074,7 +4064,7 @@ out:
 
 static void fsg_suspend(struct usb_gadget *gadget)
 {
-       struct fsg_dev          *fsg = get_gadget_data(gadget);
+       struct fsg_dev          *fsg = get_usb_function_data(gadget);
 
        DBG(fsg, "suspend\n");
        set_bit(SUSPENDED, &fsg->atomic_bitflags);
@@ -4082,7 +4072,7 @@ static void fsg_suspend(struct usb_gadget *gadget)
 
 static void fsg_resume(struct usb_gadget *gadget)
 {
-       struct fsg_dev          *fsg = get_gadget_data(gadget);
+       struct fsg_dev          *fsg = get_usb_function_data(gadget);
 
        DBG(fsg, "resume\n");
        clear_bit(SUSPENDED, &fsg->atomic_bitflags);
@@ -4091,30 +4081,23 @@ static void fsg_resume(struct usb_gadget *gadget)
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver                fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       .speed          = USB_SPEED_HIGH,
-#else
-       .speed          = USB_SPEED_FULL,
-#endif
-       .function       = (char *) longname,
+static struct usb_function fsg_driver = {
+       .name           = (char *) shortname,
+       .strings        = &stringtab,
+
+       .num_conf       = 1,
+       .config[0]      = &config_desc,
+
        .bind           = fsg_bind,
        .unbind         = fsg_unbind,
-       .disconnect     = fsg_disconnect,
+
        .setup          = fsg_setup,
+       .disconnect     = fsg_disconnect,
+
        .suspend        = fsg_suspend,
        .resume         = fsg_resume,
-
-       .driver         = {
-               .name           = (char *) shortname,
-               .owner          = THIS_MODULE,
-               // .release = ...
-               // .suspend = ...
-               // .resume = ...
-       },
 };
 
-
 static int __init fsg_alloc(void)
 {
        struct fsg_dev          *fsg;
@@ -4140,7 +4123,7 @@ static int __init fsg_init(void)
        if ((rc = fsg_alloc()) != 0)
                return rc;
        fsg = the_fsg;
-       if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
+       if ((rc = usb_func_register(&fsg_driver)) != 0)
                kref_put(&fsg->ref, fsg_release);
        return rc;
 }
@@ -4153,7 +4136,7 @@ static void __exit fsg_cleanup(void)
 
        /* Unregister the driver iff the thread hasn't already done so */
        if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
-               usb_gadget_unregister_driver(&fsg_driver);
+               usb_func_unregister(&fsg_driver);
 
        /* Wait for the thread to finish up */
        wait_for_completion(&fsg->thread_notifier);

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to