Compare commits
8 Commits
master
...
kernelport
Author | SHA1 | Date | |
---|---|---|---|
|
4c45ab8701 | ||
|
f4c9e85924 | ||
|
33863b8b96 | ||
|
b167d4f9df | ||
|
f00b4d432e | ||
|
f361b6ecc1 | ||
|
b46e18b807 | ||
|
067f8727a6 |
@ -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, ¤t->blocked, &info);
|
int sig =
|
||||||
|
dequeue_signal_lock(current, ¤t->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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user