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

📄 devio.c

📁 linux core 函数例程
💻 C
📖 第 1 页 / 共 3 页
字号:

	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->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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -