patch-2.4.0-test2 linux/drivers/usb/devio.c
Next file: linux/drivers/usb/dsbr100.c
Previous file: linux/drivers/usb/dc2xx.c
Back to the patch index
Back to the overall index
- Lines: 286
- Date:
Fri Jun 23 21:00:50 2000
- Orig file:
v2.4.0-test1/linux/drivers/usb/devio.c
- Orig date:
Wed Apr 26 16:34:08 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
@@ -187,26 +187,60 @@
ssize_t ret = 0;
unsigned len;
loff_t pos;
+ int i;
pos = *ppos;
down_read(&ps->devsem);
- if (!ps->dev)
+ if (!ps->dev) {
ret = -ENODEV;
- else if (pos < 0)
+ goto err;
+ } else if (pos < 0) {
ret = -EINVAL;
- else if (pos < sizeof(struct usb_device_descriptor)) {
+ goto err;
+ }
+
+ if (pos < sizeof(struct usb_device_descriptor)) {
len = sizeof(struct usb_device_descriptor) - pos;
if (len > nbytes)
len = nbytes;
- if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len))
+ if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) {
ret = -EFAULT;
- else {
+ goto err;
+ }
+
+ *ppos += len;
+ buf += len;
+ nbytes -= len;
+ ret += len;
+ }
+
+ pos = sizeof(struct usb_device_descriptor);
+ for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) {
+ struct usb_config_descriptor *config =
+ (struct usb_config_descriptor *)ps->dev->rawdescriptors[i];
+ unsigned int length = le16_to_cpu(config->wTotalLength);
+
+ if (*ppos < pos + length) {
+ len = length - (*ppos - pos);
+ if (len > nbytes)
+ len = nbytes;
+
+ if (copy_to_user(buf,
+ ps->dev->rawdescriptors[i] + (*ppos - pos), len)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
*ppos += len;
buf += len;
nbytes -= len;
ret += len;
}
+
+ pos += length;
}
+
+err:
up_read(&ps->devsem);
return ret;
}
@@ -376,12 +410,9 @@
}
struct usb_driver usbdevfs_driver = {
- "usbdevfs",
- driver_probe,
- driver_disconnect,
- LIST_HEAD_INIT(usbdevfs_driver.driver_list),
- NULL,
- 0
+ name: "usbdevfs",
+ probe: driver_probe,
+ disconnect: driver_disconnect,
};
static int claimintf(struct dev_state *ps, unsigned int intf)
@@ -481,6 +512,28 @@
return -ENOENT;
}
+extern struct list_head usb_driver_list;
+
+static int finddriver(struct usb_driver **driver, char *name)
+{
+ struct list_head *tmp;
+
+ tmp = usb_driver_list.next;
+ while (tmp != &usb_driver_list) {
+ struct usb_driver *d = list_entry(tmp, struct usb_driver,
+ driver_list);
+
+ if (!strcmp(d->name, name)) {
+ *driver = d;
+ return 0;
+ }
+
+ tmp = tmp->next;
+ }
+
+ return -EINVAL;
+}
+
/*
* file operations
*/
@@ -662,16 +715,77 @@
return 0;
}
+static int proc_getdriver(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_getdriver gd;
+ struct usb_interface *interface;
+ int ret;
+
+ copy_from_user_ret(&gd, arg, sizeof(gd), -EFAULT);
+ if ((ret = findintfif(ps->dev, gd.interface)) < 0)
+ return ret;
+ interface = usb_ifnum_to_if(ps->dev, gd.interface);
+ if (!interface)
+ return -EINVAL;
+ if (!interface->driver)
+ return -ENODATA;
+ strcpy(gd.driver, interface->driver->name);
+ copy_to_user_ret(arg, &gd, sizeof(gd), -EFAULT);
+ return 0;
+}
+
+static int proc_connectinfo(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_connectinfo ci;
+
+ ci.devnum = ps->dev->devnum;
+ ci.slow = ps->dev->slow;
+ copy_to_user_ret(arg, &ci, sizeof(ci), -EFAULT);
+ return 0;
+}
+
+static int proc_resetdevice(struct dev_state *ps)
+{
+ int i, ret;
+
+ ret = usb_reset_device(ps->dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ps->dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *intf = &ps->dev->actconfig->interface[i];
+
+ /* Don't simulate interfaces we've claimed */
+ if (test_bit(i, &ps->ifclaimed))
+ continue;
+
+ if (intf->driver) {
+ down(&intf->driver->serialize);
+ intf->driver->disconnect(ps->dev, intf->private_data);
+ intf->driver->probe(ps->dev, i);
+ up(&intf->driver->serialize);
+ }
+ }
+
+ return 0;
+}
+
static int proc_setintf(struct dev_state *ps, void *arg)
{
struct usbdevfs_setinterface setintf;
+ struct usb_interface *interface;
int ret;
copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT);
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
+ interface = usb_ifnum_to_if(ps->dev, setintf.interface);
+ if (!interface)
+ return -EINVAL;
+ if (interface->driver) {
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ }
if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
return -EINVAL;
return 0;
@@ -913,6 +1027,65 @@
return releaseintf(ps, intf);
}
+static int proc_ioctl (struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_ioctl ctrl;
+ int size;
+ void *buf = 0;
+ int retval = 0;
+
+ /* get input parameters and alloc buffer */
+ copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT);
+ if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
+ if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
+ return -ENOMEM;
+ if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0
+ && copy_from_user (buf, ctrl.data, size) != 0) {
+ kfree (buf);
+ return -EFAULT;
+ } else
+ memset (arg, 0, size);
+ }
+
+ /* ioctl to device */
+ if (ctrl.ifno < 0) {
+ switch (ctrl.ioctl_code) {
+ /* access/release token for issuing control messages
+ * ask a particular driver to bind/unbind, ... etc
+ */
+ }
+ retval = -ENOSYS;
+
+ /* ioctl to the driver which has claimed a given interface */
+ } else {
+ struct usb_interface *ifp = 0;
+ if (!ps->dev)
+ retval = -ENODEV;
+ else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
+ retval = -EINVAL;
+ else {
+ if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+ retval = -EINVAL;
+ else if (ifp->driver == 0 || ifp->driver->ioctl == 0)
+ retval = -ENOSYS;
+ }
+ if (retval == 0)
+ /* ifno might usefully be passed ... */
+ retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+ /* size = min (size, retval)? */
+ }
+
+ /* cleanup and return */
+ if (retval >= 0
+ && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
+ && size > 0
+ && copy_to_user (ctrl.data, buf, size) != 0)
+ retval = -EFAULT;
+ if (buf != 0)
+ kfree (buf);
+ return retval;
+}
+
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
@@ -944,6 +1117,18 @@
inode->i_mtime = CURRENT_TIME;
break;
+ case USBDEVFS_RESET:
+ ret = proc_resetdevice(ps);
+ break;
+
+ case USBDEVFS_GETDRIVER:
+ ret = proc_getdriver(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_CONNECTINFO:
+ ret = proc_connectinfo(ps, (void *)arg);
+ break;
+
case USBDEVFS_SETINTERFACE:
ret = proc_setintf(ps, (void *)arg);
break;
@@ -982,6 +1167,9 @@
ret = proc_releaseinterface(ps, (void *)arg);
break;
+ case USBDEVFS_IOCTL:
+ ret = proc_ioctl(ps, (void *) arg);
+ break;
}
up_read(&ps->devsem);
if (ret >= 0)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)