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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel