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