⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 + -