📄 devio.c
字号:
return -EFAULT; break; case USBDEVFS_URB_TYPE_ISO: /* arbitrary limit */ if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) { kfree(isopkt); return -EFAULT; } for (totlen = u = 0; u < uurb.number_of_packets; u++) { if (isopkt[u].length > 1023) { kfree(isopkt); return -EINVAL; } 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 (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.next = NULL; 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.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->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))) { printk(KERN_DEBUG "usbdevfs: 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 *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){ unsigned int i; if (as->userbuffer) if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length)) return -EFAULT; if (put_user(as->urb.status, &((struct usbdevfs_urb *)as->userurb)->status)) return -EFAULT; if (put_user(as->urb.actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length)) return -EFAULT; if (put_user(as->urb.error_count, &((struct usbdevfs_urb *)as->userurb)->error_count)) return -EFAULT; if (!(usb_pipeisoc(as->urb.pipe))) return 0; for (i = 0; i < as->urb.number_of_packets; i++) { if (put_user(as->urb.iso_frame_desc[i].actual_length, &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length)) return -EFAULT; if (put_user(as->urb.iso_frame_desc[i].status, &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) return -EFAULT; } return 0;}static int proc_reapurb(struct dev_state *ps, void *arg){ DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; void *addr; int ret; add_wait_queue(&ps->wait, &wait); while (ps->dev) { __set_current_state(TASK_INTERRUPTIBLE); if ((as = async_getcompleted(ps))) break; if (signal_pending(current)) break; up_read(&ps->devsem); schedule(); down_read(&ps->devsem); } 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 **)arg)) return -EFAULT; return 0; } if (signal_pending(current)) return -EINTR; return -EIO;}static int proc_reapurbnonblock(struct dev_state *ps, void *arg){ struct async *as; void *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 **)arg)) return -EFAULT; return 0;}static int proc_disconnectsignal(struct dev_state *ps, void *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 *arg){ unsigned int intf; int ret; if (get_user(intf, (unsigned int *)arg)) return -EFAULT; if ((ret = findintfif(ps->dev, intf)) < 0) return ret; return claimintf(ps, ret);}static int proc_releaseinterface(struct dev_state *ps, void *arg){ unsigned int intf; int ret; if (get_user(intf, (unsigned int *)arg)) return -EFAULT; if ((ret = findintfif(ps->dev, intf)) < 0) return ret; return releaseintf(ps, intf);}static int proc_ioctl (struct dev_state *ps, void *arg){ struct usbdevfs_ioctl ctrl; int size; void *buf = 0; int retval = 0; /* get input parameters and alloc buffer */ if (copy_from_user(&ctrl, (void *) 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); } } /* ioctl to device */ if (ctrl.ifno < 0) { switch (ctrl.ioctl_code) { /* access/release token for issuing control messages * ask a particular driver to bind/unbind, ... etc */ } retval = -ENOSYS; /* ioctl to the driver which has claimed a given interface */ } else { struct usb_interface *ifp = 0; if (!ps->dev) retval = -ENODEV; else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces) retval = -EINVAL; else { if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) retval = -EINVAL; else if (ifp->driver == 0 || ifp->driver->ioctl == 0) retval = -ENOSYS; } if (retval == 0) /* ifno might usefully be passed ... */ retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf); /* size = min_t(int, size, retval)? */ } /* 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;}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; int ret = -ENOIOCTLCMD; if (!(file->f_mode & FMODE_WRITE)) return -EPERM; down_read(&ps->devsem); if (!ps->dev) { up_read(&ps->devsem); return -ENODEV; } switch (cmd) { case USBDEVFS_CONTROL: ret = proc_control(ps, (void *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_BULK: ret = proc_bulk(ps, (void *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESETEP: ret = proc_resetep(ps, (void *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESET: ret = proc_resetdevice(ps); break; case USBDEVFS_CLEAR_HALT: ret = proc_clearhalt(ps, (void *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_GETDRIVER: ret = proc_getdriver(ps, (void *)arg); break; case USBDEVFS_CONNECTINFO: ret = proc_connectinfo(ps, (void *)arg); break; case USBDEVFS_SETINTERFACE: ret = proc_setintf(ps, (void *)arg); break; case USBDEVFS_SETCONFIGURATION: ret = proc_setconfig(ps, (void *)arg); break; case USBDEVFS_SUBMITURB: ret = proc_submiturb(ps, (void *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_DISCARDURB: ret = proc_unlinkurb(ps, (void *)arg); break; case USBDEVFS_REAPURB: ret = proc_reapurb(ps, (void *)arg); break; case USBDEVFS_REAPURBNDELAY: ret = proc_reapurbnonblock(ps, (void *)arg); break; case USBDEVFS_DISCSIGNAL: ret = proc_disconnectsignal(ps, (void *)arg); break; case USBDEVFS_CLAIMINTERFACE: ret = proc_claiminterface(ps, (void *)arg); break; case USBDEVFS_RELEASEINTERFACE: ret = proc_releaseinterface(ps, (void *)arg); break; case USBDEVFS_IOCTL: ret = proc_ioctl(ps, (void *) arg); break; } up_read(&ps->devsem); 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 (!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 + -