patch-2.4.0-test9 linux/drivers/usb/devio.c
Next file: linux/drivers/usb/hid.c
Previous file: linux/drivers/usb/devices.c
Back to the patch index
Back to the overall index
- Lines: 344
- Date:
Wed Sep 27 13:53:57 2000
- Orig file:
v2.4.0-test8/linux/drivers/usb/devio.c
- Orig date:
Tue Aug 29 14:09:15 2000
diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
@@ -55,113 +55,6 @@
urb_t urb;
};
-/*
- * my own sync control and bulk methods. Here to experiment
- * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE.
- */
-
-struct sync {
- wait_queue_head_t wait;
-};
-
-static void sync_completed(purb_t urb)
-{
- struct sync *s = (struct sync *)urb->context;
-
- wake_up(&s->wait);
-}
-
-static int do_sync(purb_t urb, int timeout)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long tm;
- signed long tmdiff;
- struct sync s;
- int ret;
-
- tm = jiffies+timeout;
- init_waitqueue_head(&s.wait);
- add_wait_queue(&s.wait, &wait);
- urb->context = &s;
- urb->complete = sync_completed;
- set_current_state(TASK_INTERRUPTIBLE);
- if ((ret = usb_submit_urb(urb)))
- goto out;
- while (urb->status == -EINPROGRESS) {
- tmdiff = tm - jiffies;
- if (tmdiff <= 0) {
- ret = -ETIMEDOUT;
- goto out;
- }
- if (signal_pending(current)) {
- ret = -EINTR;
- goto out;
- }
- schedule_timeout(tmdiff);
- }
- ret = urb->status;
- out:
- set_current_state(TASK_RUNNING);
- usb_unlink_urb(urb);
- remove_wait_queue(&s.wait, &wait);
- return ret;
-}
-
-static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
- __u16 value, __u16 index, void *data, __u16 size, int timeout)
-{
- urb_t *urb;
- int ret;
-
- if (!(urb = usb_alloc_urb(0)))
- return -ENOMEM;
- if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) {
- usb_free_urb(urb);
- return -ENOMEM;
- }
- urb->setup_packet[0] = requesttype;
- urb->setup_packet[1] = request;
- urb->setup_packet[2] = value;
- urb->setup_packet[3] = value >> 8;
- urb->setup_packet[4] = index;
- urb->setup_packet[5] = index >> 8;
- urb->setup_packet[6] = size;
- urb->setup_packet[7] = size >> 8;
- urb->dev = dev;
- urb->pipe = pipe;
- urb->transfer_buffer = data;
- urb->transfer_buffer_length = size;
- ret = do_sync(urb, timeout);
- //if (ret >= 0)
- // ret = urb->status;
- if (ret >= 0)
- ret = urb->actual_length;
- kfree(urb->setup_packet);
- usb_free_urb(urb);
- return ret;
-}
-
-static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
- void *data, int len, int *actual_length, int timeout)
-{
- urb_t *urb;
- int ret;
-
- if (!(urb = usb_alloc_urb(0)))
- return -ENOMEM;
- urb->dev = dev;
- urb->pipe = pipe;
- urb->transfer_buffer = data;
- urb->transfer_buffer_length = len;
- ret = do_sync(urb, timeout);
- //if (ret >= 0)
- // ret = urb->status;
- if (ret >= 0 && actual_length != NULL)
- *actual_length = urb->actual_length;
- usb_free_urb(urb);
- return ret;
-}
-
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
switch (orig) {
@@ -289,6 +182,8 @@
{
if (as->urb.transfer_buffer)
kfree(as->urb.transfer_buffer);
+ if (as->urb.setup_packet)
+ kfree(as->urb.setup_packet);
kfree(as);
}
@@ -536,6 +431,28 @@
}
#endif
+static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index)
+{
+ int ret;
+
+ switch (recip & USB_RECIP_MASK) {
+ case USB_RECIP_ENDPOINT:
+ if ((ret = findintfep(ps->dev, index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ if ((ret = findintfif(ps->dev, index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+ }
+ return 0;
+}
+
/*
* file operations
*/
@@ -609,21 +526,8 @@
if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
return -EFAULT;
- switch (ctrl.requesttype & 0x1f) {
- case USB_RECIP_ENDPOINT:
- if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
- break;
-
- case USB_RECIP_INTERFACE:
- if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
- break;
- }
+ if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index)))
+ return ret;
if (ctrl.length > PAGE_SIZE)
return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
@@ -634,7 +538,7 @@
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
if ((i > 0) && ctrl.length) {
if (copy_to_user(ctrl.data, tbuf, ctrl.length))
@@ -645,7 +549,7 @@
if (copy_from_user(tbuf, ctrl.data, ctrl.length))
return -EFAULT;
}
- i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
}
free_page((unsigned long)tbuf);
@@ -688,7 +592,7 @@
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2))
return -EFAULT;
@@ -698,7 +602,7 @@
if (copy_from_user(tbuf, bulk.data, len1))
return -EFAULT;
}
- i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
}
free_page((unsigned long)tbuf);
if (i < 0) {
@@ -840,23 +744,61 @@
{
struct usbdevfs_urb uurb;
struct usbdevfs_iso_packet_desc *isopkt = NULL;
+ struct usb_endpoint_descriptor *ep_desc;
struct async *as;
+ devrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret;
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
- if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
+ if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK))
return -EINVAL;
if (!uurb.buffer)
return -EINVAL;
if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
return -EINVAL;
- if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
+ if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+ if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ }
switch(uurb.type) {
+ case USBDEVFS_URB_TYPE_CONTROL:
+ if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) {
+ if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+ return -ENOENT;
+ if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL)
+ return -EINVAL;
+ }
+ /* min 8 byte setup packet, max arbitrary */
+ if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
+ return -EINVAL;
+ if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) {
+ kfree(dr);
+ return -EFAULT;
+ }
+ if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) {
+ kfree(dr);
+ return -EINVAL;
+ }
+ if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) {
+ kfree(dr);
+ return ret;
+ }
+ uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK);
+ uurb.number_of_packets = 0;
+ uurb.buffer_length = le16_to_cpup(&dr->length);
+ uurb.buffer += 8;
+ if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
+ kfree(dr);
+ return -EFAULT;
+ }
+ break;
+
case USBDEVFS_URB_TYPE_BULK:
uurb.number_of_packets = 0;
if (uurb.buffer_length > 16384)
@@ -896,11 +838,15 @@
if (!(as = alloc_async(uurb.number_of_packets))) {
if (isopkt)
kfree(isopkt);
+ if (dr)
+ kfree(dr);
return -ENOMEM;
}
if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
if (isopkt)
kfree(isopkt);
+ if (dr)
+ kfree(dr);
free_async(as);
return -ENOMEM;
}
@@ -909,6 +855,7 @@
as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
as->urb.transfer_flags = uurb.flags;
as->urb.transfer_buffer_length = uurb.buffer_length;
+ as->urb.setup_packet = (unsigned char*)dr;
as->urb.start_frame = uurb.start_frame;
as->urb.number_of_packets = uurb.number_of_packets;
as->urb.context = as;
@@ -963,20 +910,23 @@
if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
return -EFAULT;
if (put_user(as->urb.status,
- &((struct usbdevfs_urb *)as->userurb)->status) ||
- __put_user(as->urb.actual_length,
- &((struct usbdevfs_urb *)as->userurb)->actual_length) ||
- __put_user(as->urb.error_count,
- &((struct usbdevfs_urb *)as->userurb)->error_count))
+ &((struct usbdevfs_urb *)as->userurb)->status))
+ return -EFAULT;
+ if (put_user(as->urb.actual_length,
+ &((struct usbdevfs_urb *)as->userurb)->actual_length))
+ return -EFAULT;
+ if (put_user(as->urb.error_count,
+ &((struct usbdevfs_urb *)as->userurb)->error_count))
return -EFAULT;
if (!(usb_pipeisoc(as->urb.pipe)))
return 0;
for (i = 0; i < as->urb.number_of_packets; i++) {
if (put_user(as->urb.iso_frame_desc[i].actual_length,
- &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length) ||
- __put_user(as->urb.iso_frame_desc[i].status,
- &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
+ return -EFAULT;
+ if (put_user(as->urb.iso_frame_desc[i].status,
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
return -EFAULT;
}
return 0;
@@ -1090,7 +1040,7 @@
kfree (buf);
return -EFAULT;
} else
- memset (arg, 0, size);
+ memset (buf, 0, size);
}
/* ioctl to device */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)