Currently uses wait_for_completion() instead of 
wait_for_completion_interruptible().

Signed-off-by: Sarah Bailey <[EMAIL PROTECTED]>
---

I've sucessfully tested it on the (one) USB device I have with bulk
endpoints, but please test.

 drivers/usb/core/endpoint_fops.c |  116 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 114 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/endpoint_fops.c b/drivers/usb/core/endpoint_fops.c
index 5c85559..e7f0e97 100644
--- a/drivers/usb/core/endpoint_fops.c
+++ b/drivers/usb/core/endpoint_fops.c
@@ -1,7 +1,7 @@
 /*
  * drivers/usb/core/endpoint_fops.c
  *
- * (C) Copyright 2006 Sarah Bailey
+ * (C) Copyright 2006,2007 Sarah Bailey
  *
  * Endpoint file operations
  */
@@ -9,6 +9,8 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/usb.h>
+#include <linux/completion.h>
+#include <asm/uaccess.h>
 #include "usb.h"
 
 int endpoint_open(struct inode *inode, struct file *filp)
@@ -21,15 +23,123 @@ int endpoint_open(struct inode *inode, struct file *filp)
        return 0;
 }
 
+void callback(struct urb *urb)
+{
+       complete(urb->context);
+}
+
 ssize_t control_read(struct file * filp, char __user *buff,
                size_t count, loff_t * offp)
 {
        struct ep_device *ep_dev;
        ep_dev = filp->private_data;
-       dev_dbg(&ep_dev->dev, "%s called for %s\n", __FUNCTION__, 
ep_dev->dev.bus_id);
+       dev_dbg(&ep_dev->dev, "%s called for %s\n", __FUNCTION__,
+                       ep_dev->dev.bus_id);
        return 0;
 }
 
+ssize_t ep_read(struct file * filp, char __user *buff,
+               size_t count, loff_t * offp)
+{
+       struct ep_device *ep_dev;
+       char *k_buff;
+       struct urb *urb;
+       unsigned int pipe;
+       int retval = -ENOMEM;
+       DECLARE_COMPLETION_ONSTACK(completion);
+
+       ep_dev = filp->private_data;
+       dev_dbg(&ep_dev->dev, "%s called for %s\n", __FUNCTION__,
+                       ep_dev->dev.bus_id);
+
+       if(!usb_endpoint_xfer_bulk(ep_dev->desc))
+               return 0;
+
+       k_buff = kmalloc(count, GFP_KERNEL);
+       if(k_buff == NULL)
+               goto exit;
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if(urb == NULL)
+               goto error_urb_alloc;
+       pipe = usb_rcvbulkpipe(ep_dev->udev, ep_dev->desc->bEndpointAddress);
+       usb_fill_bulk_urb(urb, ep_dev->udev, pipe, k_buff, count,
+                       callback, &completion);
+       retval = usb_submit_urb(urb, GFP_KERNEL);
+       if(retval)
+               goto error_urb_submit;
+       wait_for_completion(&completion);
+
+       if(urb->status)
+               retval = urb->status;
+       else {
+               retval = urb->actual_length;
+               if(copy_to_user(buff, k_buff, urb->actual_length))
+                       retval = -EFAULT;
+       }
+
+error_urb_submit:
+       usb_free_urb(urb);
+error_urb_alloc:
+       kfree(k_buff);
+exit:
+       return retval;
+}
+
+ssize_t ep_write(struct file * filp, const char __user *buff,
+               size_t count, loff_t * offp)
+{
+       struct ep_device *ep_dev;
+       char *k_buff;
+       struct urb *urb;
+       unsigned int pipe;
+       int retval;
+       DECLARE_COMPLETION_ONSTACK(completion);
+
+       ep_dev = filp->private_data;
+       dev_dbg(&ep_dev->dev, "%s called for %s\n", __FUNCTION__,
+                       ep_dev->dev.bus_id);
+
+       if(!usb_endpoint_xfer_bulk(ep_dev->desc))
+               return 0;
+
+       k_buff = kmalloc(count, GFP_KERNEL);
+       if(k_buff == NULL) {
+               retval = -ENOMEM;
+               goto exit;
+       }
+       if(copy_from_user(k_buff, buff, count)) {
+               retval = -EFAULT;
+               goto error_copy_buff;
+       }
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if(urb == NULL) {
+               retval = -ENOMEM;
+               goto error_copy_buff;
+       }
+
+       // endpoint specific init
+       pipe = usb_sndbulkpipe(ep_dev->udev, ep_dev->desc->bEndpointAddress);
+       usb_fill_bulk_urb(urb, ep_dev->udev, pipe, k_buff, count,
+                       callback, &completion);
+
+       retval = usb_submit_urb(urb, GFP_KERNEL);
+       if(retval)
+               goto error_urb_submit;
+       wait_for_completion(&completion);
+
+       if(urb->status)
+               retval = urb->status;
+       else
+               retval = urb->actual_length;
+
+error_urb_submit:
+       usb_free_urb(urb);
+error_copy_buff:
+       kfree(k_buff);
+exit:
+       return retval;
+}
+
 struct file_operations usb_endpoint_control_fops = {
        .owner =        THIS_MODULE,
        .open =         endpoint_open,
@@ -39,9 +149,11 @@ struct file_operations usb_endpoint_control_fops = {
 struct file_operations usb_endpoint_in_fops = {
        .owner =        THIS_MODULE,
        .open =         endpoint_open,
+       .read =         ep_read,
 };
 
 struct file_operations usb_endpoint_out_fops = {
        .owner =        THIS_MODULE,
        .open =         endpoint_open,
+       .write =        ep_write,
 };
-- 
1.4.4.1


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to