devio.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,487 行 · 第 1/3 页
C
1,487 行
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { kfree(isopkt); return -EFAULT; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { kfree(isopkt); return -EINVAL; } totlen += isopkt[u].length; } if (totlen > 32768) { kfree(isopkt); return -EINVAL; } uurb->buffer_length = totlen; snoop(&ps->dev->dev, "iso urb\n"); break; case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; default: return -EINVAL; } if (!(as = alloc_async(uurb->number_of_packets))) { kfree(isopkt); kfree(dr); return -ENOMEM; } if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) { kfree(isopkt); 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; if (uurb->type == USBDEVFS_URB_TYPE_ISO || ps->dev->speed == USB_SPEED_HIGH) as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); else as->urb->interval = ep->desc.bInterval; 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; } 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->pid = get_pid(task_pid(current)); as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); 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; } } snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); 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_submiturb(struct dev_state *ps, void __user *arg){ struct usbdevfs_urb uurb; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);}static int proc_unlinkurb(struct dev_state *ps, void __user *arg){ struct async *as; as = async_getpending(ps, arg); if (!as) return -EINVAL; usb_kill_urb(as->urb); return 0;}static int processcompl(struct async *as, void __user * __user *arg){ struct urb *urb = as->urb; struct usbdevfs_urb __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(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);}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, 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)) { 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: 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; break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: usb_unlock_device(ps->dev); retval = bus_rescan_devices(intf->dev.bus); usb_lock_device(ps->dev); break; /* talk directly to the interface's driver */ default: 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; } } /* 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);}/* * 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 = 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(ps)) { 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; 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 = 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)) mask |= POLLERR | POLLHUP; return mask;}const struct file_operations usbdev_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, .ioctl = usbdev_ioctl, .open = usbdev_open, .release = usbdev_release,};static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE,};int __init usb_devio_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, &usbdev_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; }out: return retval;error_cdev: unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); goto out;}void usb_devio_cleanup(void){ cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?