devio.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,264 行 · 第 1/3 页
C
1,264 行
/* 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, GFP_KERNEL))) { printk(KERN_DEBUG "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 *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; 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, &((struct usbdevfs_urb *)as->userurb)->status)) return -EFAULT; if (put_user(urb->actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length)) return -EFAULT; if (put_user(urb->error_count, &((struct usbdevfs_urb *)as->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, &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length)) return -EFAULT; if (put_user(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; struct usb_interface *ifp = 0; struct usb_driver *driver = 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); } } if (!ps->dev) retval = -ENODEV; else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) retval = -EINVAL; else switch (ctrl.ioctl_code) { /* disconnect kernel driver from interface, leaving it unbound. */ case USBDEVFS_DISCONNECT: driver = ifp->driver; if (driver) { down (&driver->serialize); dbg ("disconnect '%s' from dev %d interface %d", driver->name, ps->dev->devnum, ctrl.ifno); driver->disconnect (ps->dev, ifp->private_data); usb_driver_release_interface (driver, ifp); up (&driver->serialize); } else retval = -EINVAL; break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno); break; /* talk directly to the interface's driver */ default: driver = ifp->driver; if (driver == 0 || driver->ioctl == 0) retval = -ENOSYS; else { if (ifp->driver->owner) __MOD_INC_USE_COUNT(ifp->driver->owner); /* ifno might usefully be passed ... */ retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf); /* size = min_t(int, size, retval)? */ if (ifp->driver->owner) __MOD_DEC_USE_COUNT(ifp->driver->owner); } } /* 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 + =
减小字号Ctrl + -
显示快捷键?