📄 devio.c
字号:
totlen += isopkt[u].length; } if (totlen > 32768) { kfree(isopkt); return -EINVAL; } uurb.buffer_length = totlen; break; case USBDEVFS_URB_TYPE_INTERRUPT: uurb.number_of_packets = 0; if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) return -ENOENT; if (ps->dev->speed == USB_SPEED_HIGH) interval = 1 << min (15, ep_desc->bInterval - 1); else interval = ep_desc->bInterval; 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; default: return -EINVAL; } 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; } as->urb->dev = ps->dev; 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->interval = interval; as->urb->context = as; as->urb->complete = async_completed; for (totlen = u = 0; u < uurb.number_of_packets; u++) { as->urb->iso_frame_desc[u].offset = totlen; as->urb->iso_frame_desc[u].length = isopkt[u].length; totlen += isopkt[u].length; } if (isopkt) kfree(isopkt); as->ps = ps; as->userurb = arg; if (uurb.endpoint & USB_DIR_IN) as->userbuffer = uurb.buffer; else as->userbuffer = NULL; as->signr = uurb.signr; as->ifnum = ifnum; as->task = current; if (!(uurb.endpoint & USB_DIR_IN)) { if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); async_removepending(as); free_async(as); return ret; } return 0;}static int proc_unlinkurb(struct dev_state *ps, void __user *arg){ struct async *as; as = async_getpending(ps, arg); if (!as) return -EINVAL; usb_unlink_urb(as->urb); return 0;}static int processcompl(struct async *as){ struct urb *urb = as->urb; struct usbdevfs_urb __user *userurb = 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))) return 0; 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; } return 0;}static int proc_reapurb(struct dev_state *ps, void __user *arg){ DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; void __user *addr; struct usb_device *dev = ps->dev; int ret; add_wait_queue(&ps->wait, &wait); while (connected(dev)) { __set_current_state(TASK_INTERRUPTIBLE); if ((as = async_getcompleted(ps))) break; if (signal_pending(current)) break; up(&dev->serialize); schedule(); down(&dev->serialize); } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); if (as) { ret = processcompl(as); addr = as->userurb; free_async(as); if (ret) return ret; if (put_user(addr, (void __user * __user *)arg)) return -EFAULT; return 0; } if (signal_pending(current)) return -EINTR; return -EIO;}static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg){ struct async *as; void __user *addr; int ret; if (!(as = async_getcompleted(ps))) return -EAGAIN; ret = processcompl(as); addr = as->userurb; free_async(as); if (ret) return ret; if (put_user(addr, (void __user * __user *)arg)) return -EFAULT; return 0;}static 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, void __user *arg){ struct usbdevfs_ioctl ctrl; int size; void *buf = NULL; int retval = 0; struct usb_interface *intf = NULL; struct usb_driver *driver = NULL; /* get input parameters and alloc buffer */ if (copy_from_user(&ctrl, arg, sizeof (ctrl))) return -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)) { if (copy_from_user (buf, ctrl.data, size)) { kfree (buf); return -EFAULT; } } else { memset (buf, 0, size); } } if (!connected(ps->dev)) { if (buf) kfree(buf); return -ENODEV; } if (ps->dev->state != USB_STATE_CONFIGURED) retval = -ENODEV; else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) retval = -EINVAL; else switch (ctrl.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: bus_rescan_devices(intf->dev.bus); 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 == 0 || driver->ioctl == 0) { retval = -ENOTTY; } else { retval = driver->ioctl (intf, ctrl.ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } up_read(&usb_bus_type.subsys.rwsem); } /* 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;}/* * 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; down(&dev->serialize); if (!connected(dev)) { up(&dev->serialize); 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; 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(ps, p); break; } up(&dev->serialize); 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 usbdevfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, .ioctl = usbdev_ioctl, .open = usbdev_open, .release = usbdev_release,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -