summaryrefslogtreecommitdiffstats
path: root/drivers/usb/ezusb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/ezusb.c')
-rw-r--r--drivers/usb/ezusb.c157
1 files changed, 112 insertions, 45 deletions
diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c
index 4c00ef143..59e7b4a67 100644
--- a/drivers/usb/ezusb.c
+++ b/drivers/usb/ezusb.c
@@ -27,7 +27,8 @@
* Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
* Preliminary ISO support
* 0.3 01.09.99 Async Bulk and ISO support
- * 0.4 01.09.99
+ * 0.4 01.09.99 Set callback_frames to the total number of frames to make
+ * it work with OHCI-HCD
*
*/
@@ -40,9 +41,10 @@
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <asm/uaccess.h>
+#include <linux/spinlock.h>
+
#include "usb.h"
#include "ezusb.h"
@@ -76,9 +78,9 @@ struct async {
/* --------------------------------------------------------------------- */
-extern inline unsigned ld2(unsigned int x)
+extern inline unsigned int ld2(unsigned int x)
{
- unsigned r = 0;
+ unsigned int r = 0;
if (x >= 0x10000) {
x >>= 16;
@@ -101,6 +103,17 @@ extern inline unsigned ld2(unsigned int x)
return r;
}
+#if 0
+/* why doesn't this work properly on i386? */
+extern inline unsigned int ld2(unsigned int x)
+{
+ unsigned int r;
+
+ __asm__("bsrl %1,%0" : "=r" (r) : "g" (x));
+ return r;
+}
+#endif
+
/* --------------------------------------------------------------------- */
extern __inline__ void async_removelist(struct async *as)
@@ -173,22 +186,41 @@ extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context
/* --------------------------------------------------------------------- */
-static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+static int bulk_completed(int status, void *__buffer, int rval, void *dev_id)
{
struct async *as = (struct async *)dev_id;
struct ezusb *ez = as->ez;
unsigned cnt;
-printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+printk(KERN_DEBUG "ezusb: bulk_completed: status %d rval %d\n", status, rval);
as->completed.length = rval;
- if (as->numframes > 0) {
- as->completed.status = USB_ST_NOERROR;
- for (cnt = 0; cnt < as->numframes; cnt++) {
- as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
- as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
- }
- } else
- as->completed.status = status;
+ as->completed.status = status;
+ spin_lock(&ez->lock);
+ list_del(&as->asynclist);
+ list_add_tail(&as->asynclist, &ez->async_completed);
+ spin_unlock(&ez->lock);
+ wake_up(&ez->wait);
+ return 0;
+}
+
+static int iso_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct async *as = (struct async *)dev_id;
+#else
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct async *as = (struct async *)id->context;
+#endif
+ struct ezusb *ez = as->ez;
+ unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: iso_completed: status %d rval %d\n", status, rval);
+ as->completed.length = rval;
+ as->completed.status = USB_ST_NOERROR;
+ for (cnt = 0; cnt < as->numframes; cnt++) {
+ as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+ as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+ }
spin_lock(&ez->lock);
list_del(&as->asynclist);
list_add_tail(&as->asynclist, &ez->async_completed);
@@ -264,7 +296,6 @@ static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
unsigned ret = 0;
unsigned len;
unsigned char b[64];
- devrequest dr;
int i;
if (*ppos < 0 || *ppos >= 0x10000)
@@ -280,15 +311,10 @@ static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
len = sizeof(b);
if (pos + len > 0x10000)
len = 0x10000 - pos;
- dr.requesttype = 0xc0;
- dr.request = 0xa0;
- dr.value = pos;
- dr.index = 0;
- dr.length = len;
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), &dr, b, len);
+ i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ);
if (i) {
up(&ez->mutex);
- printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+ printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i);
*ppos = pos;
if (ret)
return ret;
@@ -318,7 +344,6 @@ static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t
unsigned ret = 0;
unsigned len;
unsigned char b[64];
- devrequest dr;
int i;
if (*ppos < 0 || *ppos >= 0x10000)
@@ -341,15 +366,10 @@ static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t
return ret;
return -EFAULT;
}
- dr.requesttype = 0x40;
- dr.request = 0xa0;
- dr.value = pos;
- dr.index = 0;
- dr.length = len;
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), &dr, b, len);
+ i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ);
if (i) {
up(&ez->mutex);
- printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+ printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i);
*ppos = pos;
if (ret)
return ret;
@@ -401,7 +421,7 @@ static int ezusb_release(struct inode *inode, struct file *file)
static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
unsigned char request, unsigned short value,
unsigned short index, unsigned short length,
- void *data)
+ unsigned int timeout, void *data)
{
unsigned char *tbuf = NULL;
unsigned int pipe;
@@ -429,7 +449,7 @@ static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
}
}
}
- i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+ i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length, timeout);
if (i < 0) {
if (length > 0)
free_page((unsigned long)tbuf);
@@ -444,7 +464,7 @@ static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
return i;
}
-static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data)
{
unsigned char *tbuf = NULL;
unsigned int pipe;
@@ -473,7 +493,7 @@ static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int l
}
}
}
- ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+ ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout);
if (ret < 0) {
if (length > 0)
free_page((unsigned long)tbuf);
@@ -553,7 +573,7 @@ static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
}
}
async_newpending(as);
- if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+ if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, bulk_completed, as->data, ab->len, as))) {
async_removelist(as);
goto err_inval;
}
@@ -592,6 +612,7 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
return -EINVAL;
dsize = maxpkt * ai->framecnt;
+printk(KERN_DEBUG "ezusb: iso: dsize %d\n", dsize);
if (dsize > 65536)
return -EINVAL;
order = ld2(dsize >> PAGE_SHIFT);
@@ -603,6 +624,7 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
if (!(as = kmalloc(assize, GFP_KERNEL)))
return -ENOMEM;
+printk(KERN_DEBUG "ezusb: iso: assize %d\n", assize);
memset(as, 0, assize);
INIT_LIST_HEAD(&as->asynclist);
as->ez = ez;
@@ -630,8 +652,8 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
}
as->desc.iso->start_type = START_ABSOLUTE;
as->desc.iso->start_frame = ai->startframe;
- as->desc.iso->callback_frames = 0;
- as->desc.iso->callback_fn = async_completed;
+ as->desc.iso->callback_frames = /*0*/ai->framecnt;
+ as->desc.iso->callback_fn = iso_completed;
as->desc.iso->data = as->data;
as->desc.iso->buf_size = dsize;
for (j = 0; j < ai->framecnt; j++) {
@@ -709,9 +731,13 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
DECLARE_WAITQUEUE(wait, current);
struct usb_proc_ctrltransfer pctrl;
struct usb_proc_bulktransfer pbulk;
+ struct usb_proc_old_ctrltransfer opctrl;
+ struct usb_proc_old_bulktransfer opbulk;
struct usb_proc_setinterface psetintf;
struct ezusb_ctrltransfer ctrl;
struct ezusb_bulktransfer bulk;
+ struct ezusb_old_ctrltransfer octrl;
+ struct ezusb_old_bulktransfer obulk;
struct ezusb_setinterface setintf;
struct ezusb_asyncbulk abulk;
struct ezusb_asynciso aiso;
@@ -732,7 +758,8 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
}
ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request,
- pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+ pctrl.value, pctrl.index, pctrl.length,
+ (pctrl.timeout * HZ + 500) / 1000, pctrl.data);
break;
case USB_PROC_BULK:
@@ -740,7 +767,25 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+ ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len,
+ (pbulk.timeout * HZ + 500) / 1000, pbulk.data);
+ break;
+
+ case USB_PROC_OLD_CONTROL:
+ if (copy_from_user(&opctrl, (void *)arg, sizeof(opctrl))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_control(ez->usbdev, opctrl.requesttype, opctrl.request,
+ opctrl.value, opctrl.index, opctrl.length, HZ, opctrl.data);
+ break;
+
+ case USB_PROC_OLD_BULK:
+ if (copy_from_user(&opbulk, (void *)arg, sizeof(opbulk))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_bulk(ez->usbdev, opbulk.ep, opbulk.len, 5*HZ, opbulk.data);
break;
case USB_PROC_RESETEP:
@@ -772,12 +817,9 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- if (ctrl.dlen != ctrl.length) {
- ret = -EINVAL;
- break;
- }
ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request,
- ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+ ctrl.value, ctrl.index, ctrl.length,
+ (ctrl.timeout * HZ + 500) / 1000, ctrl.data);
break;
case EZUSB_BULK:
@@ -785,7 +827,29 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+ ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len,
+ (bulk.timeout * HZ + 500) / 1000, bulk.data);
+ break;
+
+ case EZUSB_OLD_CONTROL:
+ if (copy_from_user(&octrl, (void *)arg, sizeof(octrl))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (octrl.dlen != octrl.length) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = ezusb_control(ez->usbdev, octrl.requesttype, octrl.request,
+ octrl.value, octrl.index, octrl.length, HZ, octrl.data);
+ break;
+
+ case EZUSB_OLD_BULK:
+ if (copy_from_user(&obulk, (void *)arg, sizeof(obulk))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_bulk(ez->usbdev, obulk.ep, obulk.len, 5*HZ, obulk.data);
break;
case EZUSB_RESETEP:
@@ -813,6 +877,7 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case EZUSB_ASYNCCOMPLETED:
+ as = NULL;
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&ez->wait, &wait);
for (;;) {
@@ -928,9 +993,11 @@ static int ezusb_probe(struct usb_device *usbdev)
if (usbdev->descriptor.bNumConfigurations != 1)
return -1;
+#if 0
/* We don't handle multiple interfaces */
if (usbdev->config[0].bNumInterfaces != 1)
return -1;
+#endif
down(&ez->mutex);
if (ez->usbdev) {