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 + -
显示快捷键?