📄 devio.c
字号:
return -EINVAL;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
iface = &dev->actconfig->interface[i];
for (j = 0; j < iface->num_altsetting; j++) {
alts = &iface->altsetting[j];
if (alts->bInterfaceNumber == ifn)
return i;
}
}
return -ENOENT;
}
extern struct list_head usb_driver_list;
#if 0
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;
}
#endif
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
{
int ret;
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
switch (requesttype & 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
*/
static int usbdev_open(struct inode *inode, struct file *file)
{
struct usb_device *dev;
struct dev_state *ps;
int ret;
/*
* no locking necessary here, as both sys_open (actually filp_open)
* and the hub thread have the kernel lock
* (still acquire the kernel lock for safety)
*/
lock_kernel();
ret = -ENOENT;
dev = inode->u.generic_ip;
if (!dev)
goto out;
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
goto out;
ret = 0;
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
init_rwsem(&ps->devsem);
ps->discsignr = 0;
ps->disctask = current;
ps->disccontext = NULL;
ps->ifclaimed = 0;
wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
unlock_kernel();
return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
unsigned int i;
lock_kernel();
list_del(&ps->list);
INIT_LIST_HEAD(&ps->list);
if (ps->dev) {
for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
if (test_bit(i, &ps->ifclaimed))
releaseintf(ps, i);
}
unlock_kernel();
destroy_all_async(ps);
kfree(ps);
return 0;
}
static int proc_control(struct dev_state *ps, void *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_ctrltransfer ctrl;
unsigned int tmo;
unsigned char *tbuf;
int i, ret;
if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
return -EFAULT;
if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
return ret;
if (ctrl.wLength > PAGE_SIZE)
return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
return -ENOMEM;
tmo = (ctrl.timeout * HZ + 999) / 1000;
if (ctrl.bRequestType & 0x80) {
if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EINVAL;
}
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
if ((i > 0) && ctrl.wLength) {
if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EFAULT;
}
}
} else {
if (ctrl.wLength) {
if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EFAULT;
}
}
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
}
free_page((unsigned long)tbuf);
if (i<0) {
printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n",
dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
}
return i;
}
static int proc_bulk(struct dev_state *ps, void *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_bulktransfer bulk;
unsigned int tmo, len1, pipe;
int len2;
unsigned char *tbuf;
int i, ret;
if (copy_from_user(&bulk, (void *)arg, sizeof(bulk)))
return -EFAULT;
if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
return ret;
if ((ret = checkintf(ps, ret)))
return ret;
if (bulk.ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
else
pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
return -EINVAL;
len1 = bulk.len;
if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
return -ENOMEM;
tmo = (bulk.timeout * HZ + 999) / 1000;
if (bulk.ep & 0x80) {
if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
kfree(tbuf);
return -EINVAL;
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf);
return -EFAULT;
}
}
} else {
if (len1) {
if (copy_from_user(tbuf, bulk.data, len1)) {
kfree(tbuf);
return -EFAULT;
}
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
}
kfree(tbuf);
if (i < 0) {
printk(KERN_WARNING "usbfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n",
dev->devnum, bulk.ep, bulk.len, i);
return i;
}
return len2;
}
static int proc_resetep(struct dev_state *ps, void *arg)
{
unsigned int ep;
int ret;
if (get_user(ep, (unsigned int *)arg))
return -EFAULT;
if ((ret = findintfep(ps->dev, ep)) < 0)
return ret;
if ((ret = checkintf(ps, ret)))
return ret;
usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
return 0;
}
static int proc_clearhalt(struct dev_state *ps, void *arg)
{
unsigned int ep;
int pipe;
int ret;
if (get_user(ep, (unsigned int *)arg))
return -EFAULT;
if ((ret = findintfep(ps->dev, ep)) < 0)
return ret;
if ((ret = checkintf(ps, ret)))
return ret;
if (ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
else
pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
return usb_clear_halt(ps->dev, pipe);
}
static int proc_getdriver(struct dev_state *ps, void *arg)
{
struct usbdevfs_getdriver gd;
struct usb_interface *interface;
int ret;
if (copy_from_user(&gd, arg, sizeof(gd)))
return -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);
if (copy_to_user(arg, &gd, sizeof(gd)))
return -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->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci)))
return -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) {
const struct usb_device_id *id;
down(&intf->driver->serialize);
intf->driver->disconnect(ps->dev, intf->private_data);
id = usb_match_id(ps->dev,intf,intf->driver->id_table);
intf->driver->probe(ps->dev, i, id);
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;
if (copy_from_user(&setintf, arg, sizeof(setintf)))
return -EFAULT;
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
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;
}
static int proc_setconfig(struct dev_state *ps, void *arg)
{
unsigned int u;
if (get_user(u, (unsigned int *)arg))
return -EFAULT;
if (usb_set_configuration(ps->dev, u) < 0)
return -EINVAL;
return 0;
}
static int proc_submiturb(struct dev_state *ps, void *arg)
{
struct usbdevfs_urb uurb;
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_endpoint_descriptor *ep_desc;
struct async *as;
struct usb_ctrlrequest *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|USBDEVFS_URB_QUEUE_BULK|
USB_NO_FSBR|USB_ZERO_PACKET))
return -EINVAL;
if (!uurb.buffer)
return -EINVAL;
if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
return -EINVAL;
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(struct usb_ctrlrequest), 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->wLength) + 8)) {
kfree(dr);
return -EINVAL;
}
if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
kfree(dr);
return ret;
}
uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb.number_of_packets = 0;
uurb.buffer_length = le16_to_cpup(&dr->wLength);
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)
return -EINVAL;
if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
return -EFAULT;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -