📄 devio.c
字号:
#if 0static 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;}#endifstatic 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; if (ITYPE(inode->i_ino) != IDEVICE) goto out; dev = inode->u.usbdev_i.p.dev; 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.requesttype, ctrl.index))) return ret; if (ctrl.length > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; tmo = (ctrl.timeout * HZ + 999) / 1000; if (ctrl.requesttype & 0x80) { if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) { free_page((unsigned long)tbuf); return -EINVAL; } 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)) { free_page((unsigned long)tbuf); return -EFAULT; } } } else { if (ctrl.length) { if (copy_from_user(tbuf, ctrl.data, ctrl.length)) { free_page((unsigned long)tbuf); return -EFAULT; } } 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); if (i<0) { printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", dev->devnum, ctrl.requesttype, ctrl.request, ctrl.length, 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 (len1 > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { free_page((unsigned long)tbuf); return -EINVAL; } i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { free_page((unsigned long)tbuf); return -EFAULT; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { free_page((unsigned long)tbuf); return -EFAULT; } } i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); } free_page((unsigned long)tbuf); if (i < 0) { printk(KERN_WARNING "usbdevfs: 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; 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|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(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) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -