struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
int ep0req_status; /* P: mutex */
- struct completion epin_completion; /* P: mutex */
- struct completion epout_completion; /* P: mutex */
/* reference counter */
atomic_t ref;
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
- struct ffs_ep *ep = _ep->driver_data;
ENTER();
- /* req may be freed during unbind */
- if (ep && ep->req && likely(req->context)) {
+ if (likely(req->context)) {
struct ffs_ep *ep = _ep->driver_data;
ep->status = req->status ? req->status : req->actual;
complete(req->context);
char __user *buf, size_t len, int read)
{
struct ffs_epfile *epfile = file->private_data;
- struct ffs_data *ffs = epfile->ffs;
struct ffs_ep *ep;
char *data = NULL;
ssize_t ret, data_len;
spin_unlock_irq(&epfile->ffs->eps_lock);
ret = -EBADMSG;
} else {
- /* Fire the request */
- struct completion *done;
-
+ DECLARE_COMPLETION_ONSTACK(done);
struct usb_request *req = ep->req;
+ req->context = &done;
req->complete = ffs_epfile_io_complete;
req->buf = data;
req->length = data_len;
- if (read) {
- INIT_COMPLETION(ffs->epout_completion);
- req->context = done = &ffs->epout_completion;
- } else {
- INIT_COMPLETION(ffs->epin_completion);
- req->context = done = &ffs->epin_completion;
- }
-
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
spin_unlock_irq(&epfile->ffs->eps_lock);
if (unlikely(ret < 0)) {
/* nop */
- } else if (unlikely(wait_for_completion_interruptible(done))) {
- ret = -EINTR;
- usb_ep_dequeue(ep->ep, req);
+ } else if (unlikely(
+ wait_for_completion_interruptible(&done))) {
+ ret = -EINTR;
+ usb_ep_dequeue(ep->ep, req);
} else {
- ret = ep->status;
- if (read && ret > 0){
- ret = min_t(size_t, ret, len);
- if(unlikely(copy_to_user(buf, data, ret)))
- ret = -EFAULT;
+ /*
+ * XXX We may end up silently droping data
+ * here. Since data_len (i.e. req->length) may
+ * be bigger than len (after being rounded up
+ * to maxpacketsize), we may end up with more
+ * data then user space has space for.
+ */
+ ret = ep->status;
+ if (read && ret > 0) {
+ ret = min_t(size_t, ret, len);
+
+ if(unlikely(copy_to_user(buf, data, ret)))
+ ret = -EFAULT;
}
}
}
spin_lock_init(&ffs->eps_lock);
init_waitqueue_head(&ffs->ev.waitq);
init_completion(&ffs->ep0req_completion);
- init_completion(&ffs->epin_completion);
- init_completion(&ffs->epout_completion);
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;