Compare commits

...

8 Commits

Author SHA1 Message Date
Michal Moskal
4c45ab8701 Add more debug 2017-07-26 16:17:59 +01:00
Michal Moskal
f4c9e85924 Bring back read page alignmnet 2017-07-26 11:52:51 +01:00
Michal Moskal
33863b8b96 Fix warning 2017-07-26 11:38:31 +01:00
Michal Moskal
b167d4f9df Apply a283c03a3a 2017-07-26 11:36:52 +01:00
Michal Moskal
f00b4d432e Apply b894f60a23 2017-07-26 11:36:26 +01:00
Michal Moskal
f361b6ecc1 Apply e5fd39d9b8 2017-07-26 11:32:49 +01:00
Michal Moskal
b46e18b807 Apply aae86e8adb 2017-07-26 11:27:15 +01:00
Michal Moskal
067f8727a6 Apply b00ce11f00 2017-07-26 11:27:01 +01:00
2 changed files with 105 additions and 125 deletions

View File

@ -288,6 +288,7 @@
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include "gadget_chips.h" #include "gadget_chips.h"
@ -302,7 +303,6 @@ static const char fsg_string_interface[] = "Mass Storage";
#define FSG_NO_INTR_EP 1 #define FSG_NO_INTR_EP 1
#define FSG_BUFFHD_STATIC_BUFFER 1
#define FSG_NO_DEVICE_STRINGS 1 #define FSG_NO_DEVICE_STRINGS 1
#define FSG_NO_OTG 1 #define FSG_NO_OTG 1
#define FSG_NO_INTR_EP 1 #define FSG_NO_INTR_EP 1
@ -318,8 +318,8 @@ struct fsg_dev;
/* Data shared by all the FSG instances. */ /* Data shared by all the FSG instances. */
struct fsg_common { struct fsg_common {
struct usb_gadget *gadget; struct usb_gadget *gadget;
struct fsg_dev *fsg; struct fsg_dev *fsg, *new_fsg;
struct fsg_dev *prev_fsg; wait_queue_head_t fsg_wait;
/* filesem protects: backing files in use */ /* filesem protects: backing files in use */
struct rw_semaphore filesem; struct rw_semaphore filesem;
@ -348,7 +348,6 @@ struct fsg_common {
enum fsg_state state; /* For exception handling */ enum fsg_state state; /* For exception handling */
unsigned int exception_req_tag; unsigned int exception_req_tag;
u8 config, new_config;
enum data_direction data_dir; enum data_direction data_dir;
u32 data_size; u32 data_size;
u32 data_size_from_cmnd; u32 data_size_from_cmnd;
@ -588,7 +587,7 @@ static int fsg_setup(struct usb_function *f,
u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength); u16 w_length = le16_to_cpu(ctrl->wLength);
if (!fsg->common->config) if (!fsg_is_set(fsg->common))
return -EOPNOTSUPP; return -EOPNOTSUPP;
switch (ctrl->bRequest) { switch (ctrl->bRequest) {
@ -614,7 +613,12 @@ static int fsg_setup(struct usb_function *f,
return -EDOM; return -EDOM;
VDBG(fsg, "get max LUN\n"); VDBG(fsg, "get max LUN\n");
*(u8 *) req->buf = fsg->common->nluns - 1; *(u8 *) req->buf = fsg->common->nluns - 1;
return 1;
/* Respond with data/status */
req->length = min((u16)1, w_length);
fsg->common->ep0req_name =
ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
return ep0_queue(fsg->common);
} }
VDBG(fsg, VDBG(fsg,
@ -705,9 +709,7 @@ static int do_read(struct fsg_common *common)
u32 amount_left; u32 amount_left;
loff_t file_offset, file_offset_tmp; loff_t file_offset, file_offset_tmp;
unsigned int amount; unsigned int amount;
// partial_page handling causes hangs unsigned int partial_page;
// same thing in do_write() --mmoskal
//unsigned int partial_page;
ssize_t nread; ssize_t nread;
/* Get the starting Logical Block Address and check that it's /* Get the starting Logical Block Address and check that it's
@ -752,12 +754,10 @@ static int do_read(struct fsg_common *common)
amount = min(amount_left, FSG_BUFLEN); amount = min(amount_left, FSG_BUFLEN);
amount = min((loff_t) amount, amount = min((loff_t) amount,
curlun->file_length - file_offset); curlun->file_length - file_offset);
/*
partial_page = file_offset & (PAGE_CACHE_SIZE - 1); partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0) if (partial_page > 0)
amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
partial_page); partial_page);
*/
/* Wait for the next buffer to become available */ /* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill; bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
@ -840,7 +840,7 @@ static int do_write(struct fsg_common *common)
u32 amount_left_to_req, amount_left_to_write; u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp; loff_t usb_offset, file_offset, file_offset_tmp;
unsigned int amount; unsigned int amount;
//unsigned int partial_page; unsigned int partial_page;
ssize_t nwritten; ssize_t nwritten;
int rc; int rc;
@ -904,12 +904,10 @@ static int do_write(struct fsg_common *common)
amount = min(amount_left_to_req, FSG_BUFLEN); amount = min(amount_left_to_req, FSG_BUFLEN);
amount = min((loff_t) amount, curlun->file_length - amount = min((loff_t) amount, curlun->file_length -
usb_offset); usb_offset);
/*
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0) if (partial_page > 0)
amount = min(amount, amount = min(amount,
(unsigned int) PAGE_CACHE_SIZE - partial_page); (unsigned int) PAGE_CACHE_SIZE - partial_page);
*/
if (amount == 0) { if (amount == 0) {
get_some_more = 0; get_some_more = 0;
@ -940,6 +938,7 @@ static int do_write(struct fsg_common *common)
bh->outreq->length = amount; bh->outreq->length = amount;
bh->bulk_out_intended_length = amount; bh->bulk_out_intended_length = amount;
bh->outreq->short_not_ok = 1; bh->outreq->short_not_ok = 1;
printk("write transfer %d\n", amount);
START_TRANSFER_OR(common, bulk_out, bh->outreq, START_TRANSFER_OR(common, bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state) &bh->outreq_busy, &bh->state)
/* Don't know what to do if /* Don't know what to do if
@ -1016,10 +1015,14 @@ static int do_write(struct fsg_common *common)
continue; continue;
} }
printk("before sleep\n");
/* Wait for something to happen */ /* Wait for something to happen */
rc = sleep_thread(common); rc = sleep_thread(common);
if (rc) if (rc)
return rc; return rc;
printk("after sleep\n");
} }
return -EIO; /* No default reply */ return -EIO; /* No default reply */
@ -2263,24 +2266,20 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
return -ENOMEM; return -ENOMEM;
} }
/* /* Reset interface setting and re-init endpoint state (toggle etc). */
* Reset interface setting and re-init endpoint state (toggle etc). static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
* Call with altsetting < 0 to disable the interface. The only other
* available altsetting is 0, which enables the interface.
*/
static int do_set_interface(struct fsg_common *common, int altsetting)
{ {
int rc = 0; const struct usb_endpoint_descriptor *d;
int i; struct fsg_dev *fsg;
const struct usb_endpoint_descriptor *d; int i, rc = 0;
if (common->running) if (common->running)
DBG(common, "reset interface\n"); DBG(common, "reset interface\n");
reset: reset:
/* Deallocate the requests */ /* Deallocate the requests */
if (common->prev_fsg) { if (common->fsg) {
struct fsg_dev *fsg = common->prev_fsg; fsg = common->fsg;
for (i = 0; i < FSG_NUM_BUFFERS; ++i) { for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i]; struct fsg_buffhd *bh = &common->buffhds[i];
@ -2305,88 +2304,53 @@ reset:
fsg->bulk_out_enabled = 0; fsg->bulk_out_enabled = 0;
} }
common->prev_fsg = 0; common->fsg = NULL;
wake_up(&common->fsg_wait);
} }
common->running = 0; common->running = 0;
if (altsetting < 0 || rc != 0) if (!new_fsg || rc)
return rc; return rc;
DBG(common, "set interface %d\n", altsetting); common->fsg = new_fsg;
fsg = common->fsg;
if (fsg_is_set(common)) { /* Enable the endpoints */
struct fsg_dev *fsg = common->fsg; d = fsg_ep_desc(common->gadget,
common->prev_fsg = common->fsg; &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
rc = enable_endpoint(common, fsg->bulk_in, d);
if (rc)
goto reset;
fsg->bulk_in_enabled = 1;
/* Enable the endpoints */ d = fsg_ep_desc(common->gadget,
d = fsg_ep_desc(common->gadget, &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); rc = enable_endpoint(common, fsg->bulk_out, d);
rc = enable_endpoint(common, fsg->bulk_in, d); if (rc)
goto reset;
fsg->bulk_out_enabled = 1;
common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
/* Allocate the requests */
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
if (rc) if (rc)
goto reset; goto reset;
fsg->bulk_in_enabled = 1; rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
d = fsg_ep_desc(common->gadget,
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
rc = enable_endpoint(common, fsg->bulk_out, d);
if (rc) if (rc)
goto reset; goto reset;
fsg->bulk_out_enabled = 1; bh->inreq->buf = bh->outreq->buf = bh->buf;
common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); bh->inreq->context = bh->outreq->context = bh;
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); bh->inreq->complete = bulk_in_complete;
bh->outreq->complete = bulk_out_complete;
/* Allocate the requests */
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
if (rc)
goto reset;
rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
if (rc)
goto reset;
bh->inreq->buf = bh->outreq->buf = bh->buf;
bh->inreq->context = bh->outreq->context = bh;
bh->inreq->complete = bulk_in_complete;
bh->outreq->complete = bulk_out_complete;
}
common->running = 1;
for (i = 0; i < common->nluns; ++i)
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
return rc;
} else {
return -EIO;
}
}
/*
* Change our operational configuration. This code must agree with the code
* that returns config descriptors, and with interface altsetting code.
*
* It's also responsible for power management interactions. Some
* configurations might not work with our current power sources.
* For now we just assume the gadget is always self-powered.
*/
static int do_set_config(struct fsg_common *common, u8 new_config)
{
int rc = 0;
/* Disable the single interface */
if (common->config != 0) {
DBG(common, "reset config\n");
common->config = 0;
rc = do_set_interface(common, -1);
} }
/* Enable the interface */ common->running = 1;
if (new_config != 0) { for (i = 0; i < common->nluns; ++i)
common->config = new_config; common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
rc = do_set_interface(common, 0);
if (rc != 0)
common->config = 0; /* Reset on errors */
}
return rc; return rc;
} }
@ -2397,9 +2361,7 @@ static int do_set_config(struct fsg_common *common, u8 new_config)
static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{ {
struct fsg_dev *fsg = fsg_from_func(f); struct fsg_dev *fsg = fsg_from_func(f);
fsg->common->prev_fsg = fsg->common->fsg; fsg->common->new_fsg = fsg;
fsg->common->fsg = fsg;
fsg->common->new_config = 1;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
return 0; return 0;
} }
@ -2407,9 +2369,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
static void fsg_disable(struct usb_function *f) static void fsg_disable(struct usb_function *f)
{ {
struct fsg_dev *fsg = fsg_from_func(f); struct fsg_dev *fsg = fsg_from_func(f);
fsg->common->prev_fsg = fsg->common->fsg; fsg->common->new_fsg = NULL;
fsg->common->fsg = fsg;
fsg->common->new_config = 0;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
} }
@ -2419,19 +2379,17 @@ static void fsg_disable(struct usb_function *f)
static void handle_exception(struct fsg_common *common) static void handle_exception(struct fsg_common *common)
{ {
siginfo_t info; siginfo_t info;
int sig;
int i; int i;
struct fsg_buffhd *bh; struct fsg_buffhd *bh;
enum fsg_state old_state; enum fsg_state old_state;
u8 new_config;
struct fsg_lun *curlun; struct fsg_lun *curlun;
unsigned int exception_req_tag; unsigned int exception_req_tag;
int rc;
/* Clear the existing signals. Anything but SIGUSR1 is converted /* Clear the existing signals. Anything but SIGUSR1 is converted
* into a high-priority EXIT exception. */ * into a high-priority EXIT exception. */
for (;;) { for (;;) {
sig = dequeue_signal_lock(current, &current->blocked, &info); int sig =
dequeue_signal_lock(current, &current->blocked, &info);
if (!sig) if (!sig)
break; break;
if (sig != SIGUSR1) { if (sig != SIGUSR1) {
@ -2442,7 +2400,7 @@ static void handle_exception(struct fsg_common *common)
} }
/* Cancel all the pending transfers */ /* Cancel all the pending transfers */
if (fsg_is_set(common)) { if (likely(common->fsg)) {
for (i = 0; i < FSG_NUM_BUFFERS; ++i) { for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
bh = &common->buffhds[i]; bh = &common->buffhds[i];
if (bh->inreq_busy) if (bh->inreq_busy)
@ -2483,7 +2441,6 @@ static void handle_exception(struct fsg_common *common)
common->next_buffhd_to_fill = &common->buffhds[0]; common->next_buffhd_to_fill = &common->buffhds[0];
common->next_buffhd_to_drain = &common->buffhds[0]; common->next_buffhd_to_drain = &common->buffhds[0];
exception_req_tag = common->exception_req_tag; exception_req_tag = common->exception_req_tag;
new_config = common->new_config;
old_state = common->state; old_state = common->state;
if (old_state == FSG_STATE_ABORT_BULK_OUT) if (old_state == FSG_STATE_ABORT_BULK_OUT)
@ -2533,20 +2490,12 @@ static void handle_exception(struct fsg_common *common)
break; break;
case FSG_STATE_CONFIG_CHANGE: case FSG_STATE_CONFIG_CHANGE:
rc = do_set_config(common, new_config); do_set_interface(common, common->new_fsg);
if (common->ep0_req_tag != exception_req_tag)
break;
if (rc != 0) { /* STALL on errors */
DBG(common, "ep0 set halt\n");
usb_ep_set_halt(common->ep0);
} else { /* Complete the status stage */
ep0_queue(common);
}
break; break;
case FSG_STATE_EXIT: case FSG_STATE_EXIT:
case FSG_STATE_TERMINATED: case FSG_STATE_TERMINATED:
do_set_config(common, 0); /* Free resources */ do_set_interface(common, NULL); /* Free resources */
spin_lock_irq(&common->lock); spin_lock_irq(&common->lock);
common->state = FSG_STATE_TERMINATED; /* Stop the thread */ common->state = FSG_STATE_TERMINATED; /* Stop the thread */
spin_unlock_irq(&common->lock); spin_unlock_irq(&common->lock);
@ -2720,7 +2669,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
common->free_storage_on_release = 1; common->free_storage_on_release = 1;
} else { } else {
memset(common, 0, sizeof common); memset(common, 0, sizeof *common);
common->free_storage_on_release = 0; common->free_storage_on_release = 0;
} }
@ -2798,13 +2747,19 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
/* Data buffers cyclic list */ /* Data buffers cyclic list */
/* Buffers in buffhds are static -- no need for additional
* allocation. */
bh = common->buffhds; bh = common->buffhds;
i = FSG_NUM_BUFFERS - 1; i = FSG_NUM_BUFFERS;
goto buffhds_first_it;
do { do {
bh->next = bh + 1; bh->next = bh + 1;
} while (++bh, --i); ++bh;
buffhds_first_it:
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
if (unlikely(!bh->buf)) {
rc = -ENOMEM;
goto error_release;
}
} while (--i);
bh->next = common->buffhds; bh->next = common->buffhds;
@ -2858,6 +2813,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
goto error_release; goto error_release;
} }
init_completion(&common->thread_notifier); init_completion(&common->thread_notifier);
init_waitqueue_head(&common->fsg_wait);
#undef OR #undef OR
@ -2912,6 +2868,7 @@ static void fsg_common_release(struct kref *ref)
container_of(ref, struct fsg_common, ref); container_of(ref, struct fsg_common, ref);
unsigned i = common->nluns; unsigned i = common->nluns;
struct fsg_lun *lun = common->luns; struct fsg_lun *lun = common->luns;
struct fsg_buffhd *bh;
/* If the thread isn't already dead, tell it to exit now */ /* If the thread isn't already dead, tell it to exit now */
if (common->state != FSG_STATE_TERMINATED) { if (common->state != FSG_STATE_TERMINATED) {
@ -2933,6 +2890,13 @@ static void fsg_common_release(struct kref *ref)
} }
kfree(common->luns); kfree(common->luns);
i = FSG_NUM_BUFFERS;
bh = common->buffhds;
do {
kfree(bh->buf);
} while (++bh, --i);
if (common->free_storage_on_release) if (common->free_storage_on_release)
kfree(common); kfree(common);
} }
@ -2944,9 +2908,19 @@ static void fsg_common_release(struct kref *ref)
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
{ {
struct fsg_dev *fsg = fsg_from_func(f); struct fsg_dev *fsg = fsg_from_func(f);
struct fsg_common *common = fsg->common;
DBG(fsg, "unbind\n"); DBG(fsg, "unbind\n");
fsg_common_put(fsg->common);
if (fsg->common->fsg == fsg) {
fsg->common->new_fsg = NULL;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
/* FIXME: make interruptible or killable somehow? */
wait_event(common->fsg_wait, common->fsg != fsg);
}
fsg_common_put(common);
kfree(fsg); kfree(fsg);
} }
@ -2955,7 +2929,6 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
{ {
struct fsg_dev *fsg = fsg_from_func(f); struct fsg_dev *fsg = fsg_from_func(f);
struct usb_gadget *gadget = c->cdev->gadget; struct usb_gadget *gadget = c->cdev->gadget;
int rc;
int i; int i;
struct usb_ep *ep; struct usb_ep *ep;
@ -2981,6 +2954,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
ep->driver_data = fsg->common; /* claim the endpoint */ ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_out = ep; fsg->bulk_out = ep;
/* Copy descriptors */
f->descriptors = usb_copy_descriptors(fsg_fs_function);
if (unlikely(!f->descriptors)) {
usb_free_descriptors(f->descriptors);
return -ENOMEM;
}
if (gadget_is_dualspeed(gadget)) { if (gadget_is_dualspeed(gadget)) {
/* Assume endpoint addresses are the same for both speeds */ /* Assume endpoint addresses are the same for both speeds */
fsg_hs_bulk_in_desc.bEndpointAddress = fsg_hs_bulk_in_desc.bEndpointAddress =
@ -2994,9 +2974,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
autoconf_fail: autoconf_fail:
ERROR(fsg, "unable to autoconfigure all endpoints\n"); ERROR(fsg, "unable to autoconfigure all endpoints\n");
rc = -ENOTSUPP;
fsg_unbind(c, f); fsg_unbind(c, f);
return rc; return -ENOTSUPP;
} }

View File

@ -73,6 +73,7 @@
#undef DUMP_MSGS #undef DUMP_MSGS
#endif /* !DEBUG */ #endif /* !DEBUG */
#define VERBOSE_DEBUG
#ifdef VERBOSE_DEBUG #ifdef VERBOSE_DEBUG
#define VLDBG LDBG #define VLDBG LDBG
#else #else