📄 devio.c
字号:
return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; if (usb_pipeisoc(urb->pipe)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) return -EFAULT; if (put_user(urb->iso_frame_desc[i].status, &userurb->iso_frame_desc[i].status)) return -EFAULT; } } free_async(as); if (put_user(addr, (void __user * __user *)arg)) return -EFAULT; return 0;}static struct async* reap_as(struct dev_state *ps){ DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; struct usb_device *dev = ps->dev; add_wait_queue(&ps->wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if ((as = async_getcompleted(ps))) break; if (signal_pending(current)) break; usb_unlock_device(dev); schedule(); usb_lock_device(dev); } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); return as;}static int proc_reapurb(struct dev_state *ps, void __user *arg){ struct async *as = reap_as(ps); if (as) return processcompl(as, (void __user * __user *)arg); if (signal_pending(current)) return -EINTR; return -EIO;}static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg){ struct async *as; if (!(as = async_getcompleted(ps))) return -EAGAIN; return processcompl(as, (void __user * __user *)arg);}#ifdef CONFIG_COMPATstatic int get_urb32(struct usbdevfs_urb *kurb, struct usbdevfs_urb32 __user *uurb){ __u32 uptr; if (get_user(kurb->type, &uurb->type) || __get_user(kurb->endpoint, &uurb->endpoint) || __get_user(kurb->status, &uurb->status) || __get_user(kurb->flags, &uurb->flags) || __get_user(kurb->buffer_length, &uurb->buffer_length) || __get_user(kurb->actual_length, &uurb->actual_length) || __get_user(kurb->start_frame, &uurb->start_frame) || __get_user(kurb->number_of_packets, &uurb->number_of_packets) || __get_user(kurb->error_count, &uurb->error_count) || __get_user(kurb->signr, &uurb->signr)) return -EFAULT; if (__get_user(uptr, &uurb->buffer)) return -EFAULT; kurb->buffer = compat_ptr(uptr); if (__get_user(uptr, &uurb->buffer)) return -EFAULT; kurb->usercontext = compat_ptr(uptr); return 0;}static int proc_submiturb_compat(struct dev_state *ps, void __user *arg){ struct usbdevfs_urb uurb; if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) return -EFAULT; return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);}static int processcompl_compat(struct async *as, void __user * __user *arg){ struct urb *urb = as->urb; struct usbdevfs_urb32 __user *userurb = as->userurb; void __user *addr = as->userurb; unsigned int i; if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; if (put_user(urb->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; if (usb_pipeisoc(urb->pipe)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) return -EFAULT; if (put_user(urb->iso_frame_desc[i].status, &userurb->iso_frame_desc[i].status)) return -EFAULT; } } free_async(as); if (put_user((u32)(u64)addr, (u32 __user *)arg)) return -EFAULT; return 0;}static int proc_reapurb_compat(struct dev_state *ps, void __user *arg){ struct async *as = reap_as(ps); if (as) return processcompl_compat(as, (void __user * __user *)arg); if (signal_pending(current)) return -EINTR; return -EIO;}static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg){ struct async *as; if (!(as = async_getcompleted(ps))) return -EAGAIN; return processcompl_compat(as, (void __user * __user *)arg);}#endifstatic int proc_disconnectsignal(struct dev_state *ps, void __user *arg){ struct usbdevfs_disconnectsignal ds; if (copy_from_user(&ds, arg, sizeof(ds))) return -EFAULT; if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX)) return -EINVAL; ps->discsignr = ds.signr; ps->disccontext = ds.context; return 0;}static int proc_claiminterface(struct dev_state *ps, void __user *arg){ unsigned int ifnum; if (get_user(ifnum, (unsigned int __user *)arg)) return -EFAULT; return claimintf(ps, ifnum);}static int proc_releaseinterface(struct dev_state *ps, void __user *arg){ unsigned int ifnum; int ret; if (get_user(ifnum, (unsigned int __user *)arg)) return -EFAULT; if ((ret = releaseintf(ps, ifnum)) < 0) return ret; destroy_async_on_interface (ps, ifnum); return 0;}static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl){ int size; void *buf = NULL; int retval = 0; struct usb_interface *intf = NULL; struct usb_driver *driver = NULL; /* alloc buffer */ if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) return -ENOMEM; if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { if (copy_from_user (buf, ctl->data, size)) { kfree(buf); return -EFAULT; } } else { memset (buf, 0, size); } } if (!connected(ps->dev)) { kfree(buf); return -ENODEV; } if (ps->dev->state != USB_STATE_CONFIGURED) retval = -EHOSTUNREACH; else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) retval = -EINVAL; else switch (ctl->ioctl_code) { /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: down_write(&usb_bus_type.subsys.rwsem); if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); dev_dbg (&intf->dev, "disconnect by usbfs\n"); usb_driver_release_interface(driver, intf); } else retval = -ENODATA; up_write(&usb_bus_type.subsys.rwsem); break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: usb_unlock_device(ps->dev); usb_lock_all_devices(); bus_rescan_devices(intf->dev.bus); usb_unlock_all_devices(); usb_lock_device(ps->dev); break; /* talk directly to the interface's driver */ default: down_read(&usb_bus_type.subsys.rwsem); if (intf->dev.driver) driver = to_usb_driver(intf->dev.driver); if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { retval = driver->ioctl (intf, ctl->ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } up_read(&usb_bus_type.subsys.rwsem); } /* cleanup and return */ if (retval >= 0 && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 && size > 0 && copy_to_user (ctl->data, buf, size) != 0) retval = -EFAULT; kfree(buf); return retval;}static int proc_ioctl_default(struct dev_state *ps, void __user *arg){ struct usbdevfs_ioctl ctrl; if (copy_from_user(&ctrl, arg, sizeof (ctrl))) return -EFAULT; return proc_ioctl(ps, &ctrl);}#ifdef CONFIG_COMPATstatic int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg){ struct usbdevfs_ioctl32 __user *uioc; struct usbdevfs_ioctl ctrl; u32 udata; uioc = compat_ptr((long)arg); if (get_user(ctrl.ifno, &uioc->ifno) || get_user(ctrl.ioctl_code, &uioc->ioctl_code) || __get_user(udata, &uioc->data)) return -EFAULT; ctrl.data = compat_ptr(udata); return proc_ioctl(ps, &ctrl);}#endif/* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from * changing. But there's no mechanism to ensure that... */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; struct usb_device *dev = ps->dev; void __user *p = (void __user *)arg; int ret = -ENOTTY; if (!(file->f_mode & FMODE_WRITE)) return -EPERM; usb_lock_device(dev); if (!connected(dev)) { usb_unlock_device(dev); return -ENODEV; } switch (cmd) { case USBDEVFS_CONTROL: snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); ret = proc_control(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_BULK: snoop(&dev->dev, "%s: BULK\n", __FUNCTION__); ret = proc_bulk(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESETEP: snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__); ret = proc_resetep(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESET: snoop(&dev->dev, "%s: RESET\n", __FUNCTION__); ret = proc_resetdevice(ps); break; case USBDEVFS_CLEAR_HALT: snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__); ret = proc_clearhalt(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_GETDRIVER: snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__); ret = proc_getdriver(ps, p); break; case USBDEVFS_CONNECTINFO: snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__); ret = proc_connectinfo(ps, p); break; case USBDEVFS_SETINTERFACE: snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__); ret = proc_setintf(ps, p); break; case USBDEVFS_SETCONFIGURATION: snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__); ret = proc_setconfig(ps, p); break; case USBDEVFS_SUBMITURB: snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__); ret = proc_submiturb(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break;#ifdef CONFIG_COMPAT case USBDEVFS_SUBMITURB32: snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__); ret = proc_submiturb_compat(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_REAPURB32: snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__); ret = proc_reapurb_compat(ps, p); break; case USBDEVFS_REAPURBNDELAY32: snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__); ret = proc_reapurbnonblock_compat(ps, p); break; case USBDEVFS_IOCTL32: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); ret = proc_ioctl_compat(ps, (compat_uptr_t)(long)p); break;#endif case USBDEVFS_DISCARDURB: snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); ret = proc_unlinkurb(ps, p); break; case USBDEVFS_REAPURB: snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__); ret = proc_reapurb(ps, p); break; case USBDEVFS_REAPURBNDELAY: snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__); ret = proc_reapurbnonblock(ps, p); break; case USBDEVFS_DISCSIGNAL: snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__); ret = proc_disconnectsignal(ps, p); break; case USBDEVFS_CLAIMINTERFACE: snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__); ret = proc_claiminterface(ps, p); break; case USBDEVFS_RELEASEINTERFACE: snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__); ret = proc_releaseinterface(ps, p); break; case USBDEVFS_IOCTL: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); ret = proc_ioctl_default(ps, p); break; } usb_unlock_device(dev); if (ret >= 0) inode->i_atime = CURRENT_TIME; return ret;}/* No kernel lock - fine */static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait){ struct dev_state *ps = (struct dev_state *)file->private_data; unsigned int mask = 0; poll_wait(file, &ps->wait, wait); if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) mask |= POLLOUT | POLLWRNORM; if (!connected(ps->dev)) mask |= POLLERR | POLLHUP; return mask;}struct file_operations usbfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, .ioctl = usbdev_ioctl, .open = usbdev_open, .release = usbdev_release,};static void usbdev_add(struct usb_device *dev){ int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); dev->class_dev->class_data = dev;}static void usbdev_remove(struct usb_device *dev){ class_device_unregister(dev->class_dev);}static int usbdev_notify(struct notifier_block *self, unsigned long action, void *dev){ switch (action) { case USB_DEVICE_ADD: usbdev_add(dev); break; case USB_DEVICE_REMOVE: usbdev_remove(dev); break; } return NOTIFY_OK;}static struct notifier_block usbdev_nb = { .notifier_call = usbdev_notify,};static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE,};int __init usbdev_init(void){ int retval; retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX, "usb_device"); if (retval) { err("unable to register minors for usb_device"); goto out; } cdev_init(&usb_device_cdev, &usbfs_device_file_operations); retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); if (retval) { err("unable to get usb_device major %d", USB_DEVICE_MAJOR); goto error_cdev; } usb_device_class = class_create(THIS_MODULE, "usb_device"); if (IS_ERR(usb_device_class)) { err("unable to register usb_device class"); retval = PTR_ERR(usb_device_class); goto error_class; } usb_register_notify(&usbdev_nb);out: return retval;error_class: usb_device_class = NULL; cdev_del(&usb_device_cdev);error_cdev: unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); goto out;}void usbdev_cleanup(void){ usb_unregister_notify(&usbdev_nb); class_destroy(usb_device_class); cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -