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

📄 devio.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************//* *      devio.c  --  User space communication with USB devices. * *      Copyright (C) 1999-2000  Thomas Sailer (sailer@ife.ee.ethz.ch) * *      This program is free software; you can redistribute it and/or modify *      it under the terms of the GNU General Public License as published by *      the Free Software Foundation; either version 2 of the License, or *      (at your option) any later version. * *      This program is distributed in the hope that it will be useful, *      but WITHOUT ANY WARRANTY; without even the implied warranty of *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *      GNU General Public License for more details. * *      You should have received a copy of the GNU General Public License *      along with this program; if not, write to the Free Software *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *  $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $ * *  This file implements the usbdevfs/x/y files, where *  x is the bus number and y the device number. * *  It allows user space programs/"drivers" to communicate directly *  with USB devices without intervening kernel driver. * *  Revision history *    22.12.1999   0.1   Initial release (split from proc_usb.c) *    04.01.2000   0.2   Turned into its own filesystem *//*****************************************************************************/#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/signal.h>#include <linux/poll.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/usbdevice_fs.h>#include <asm/uaccess.h>#include <asm/byteorder.h>#include <linux/moduleparam.h>#include "hcd.h"	/* for usbcore internals */#include "usb.h"struct async {	struct list_head asynclist;	struct dev_state *ps;	struct task_struct *task;	unsigned int signr;	unsigned int ifnum;	void __user *userbuffer;	void __user *userurb;	struct urb *urb;};static int usbfs_snoop = 0;module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");#define snoop(dev, format, arg...)				\	do {							\		if (usbfs_snoop)				\			dev_info( dev , format , ## arg);	\	} while (0)static inline int connected (struct usb_device *dev){	return dev->state != USB_STATE_NOTATTACHED;}static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig){	loff_t ret;	lock_kernel();	switch (orig) {	case 0:		file->f_pos = offset;		ret = file->f_pos;		break;	case 1:		file->f_pos += offset;		ret = file->f_pos;		break;	case 2:	default:		ret = -EINVAL;	}	unlock_kernel();	return ret;}static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos){	struct dev_state *ps = (struct dev_state *)file->private_data;	struct usb_device *dev = ps->dev;	ssize_t ret = 0;	unsigned len;	loff_t pos;	int i;	pos = *ppos;	down(&dev->serialize);	if (!connected(dev)) {		ret = -ENODEV;		goto err;	} else if (pos < 0) {		ret = -EINVAL;		goto err;	}	if (pos < sizeof(struct usb_device_descriptor)) {		len = sizeof(struct usb_device_descriptor) - pos;		if (len > nbytes)			len = nbytes;		if (copy_to_user(buf, ((char *)&dev->descriptor) + pos, len)) {			ret = -EFAULT;			goto err;		}		*ppos += len;		buf += len;		nbytes -= len;		ret += len;	}	pos = sizeof(struct usb_device_descriptor);	for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {		struct usb_config_descriptor *config =			(struct usb_config_descriptor *)dev->rawdescriptors[i];		unsigned int length = le16_to_cpu(config->wTotalLength);		if (*ppos < pos + length) {			/* The descriptor may claim to be longer than it			 * really is.  Here is the actual allocated length. */			unsigned alloclen =				dev->config[i].desc.wTotalLength;			len = length - (*ppos - pos);			if (len > nbytes)				len = nbytes;			/* Simply don't write (skip over) unallocated parts */			if (alloclen > (*ppos - pos)) {				alloclen -= (*ppos - pos);				if (copy_to_user(buf,				    dev->rawdescriptors[i] + (*ppos - pos),				    min(len, alloclen))) {					ret = -EFAULT;					goto err;				}			}			*ppos += len;			buf += len;			nbytes -= len;			ret += len;		}		pos += length;	}err:	up(&dev->serialize);	return ret;}/* * async list handling */static struct async *alloc_async(unsigned int numisoframes){        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);        struct async *as = kmalloc(assize, GFP_KERNEL);        if (!as)                return NULL;        memset(as, 0, assize);	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);	if (!as->urb) {		kfree(as);		return NULL;	}        return as;}static void free_async(struct async *as){        if (as->urb->transfer_buffer)                kfree(as->urb->transfer_buffer);        if (as->urb->setup_packet)                kfree(as->urb->setup_packet);	usb_free_urb(as->urb);        kfree(as);}static inline void async_newpending(struct async *as){        struct dev_state *ps = as->ps;        unsigned long flags;                spin_lock_irqsave(&ps->lock, flags);        list_add_tail(&as->asynclist, &ps->async_pending);        spin_unlock_irqrestore(&ps->lock, flags);}static inline void async_removepending(struct async *as){        struct dev_state *ps = as->ps;        unsigned long flags;                spin_lock_irqsave(&ps->lock, flags);        list_del_init(&as->asynclist);        spin_unlock_irqrestore(&ps->lock, flags);}static inline struct async *async_getcompleted(struct dev_state *ps){        unsigned long flags;        struct async *as = NULL;        spin_lock_irqsave(&ps->lock, flags);        if (!list_empty(&ps->async_completed)) {                as = list_entry(ps->async_completed.next, struct async, asynclist);                list_del_init(&as->asynclist);        }        spin_unlock_irqrestore(&ps->lock, flags);        return as;}static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb){        unsigned long flags;        struct async *as;        spin_lock_irqsave(&ps->lock, flags);	list_for_each_entry(as, &ps->async_pending, asynclist)		if (as->userurb == userurb) {			list_del_init(&as->asynclist);			spin_unlock_irqrestore(&ps->lock, flags);			return as;		}        spin_unlock_irqrestore(&ps->lock, flags);        return NULL;}static void async_completed(struct urb *urb, struct pt_regs *regs){        struct async *as = (struct async *)urb->context;        struct dev_state *ps = as->ps;	struct siginfo sinfo;        spin_lock(&ps->lock);        list_move_tail(&as->asynclist, &ps->async_completed);        spin_unlock(&ps->lock);	if (as->signr) {		sinfo.si_signo = as->signr;		sinfo.si_errno = as->urb->status;		sinfo.si_code = SI_ASYNCIO;		sinfo.si_addr = as->userurb;		send_sig_info(as->signr, &sinfo, as->task);	}        wake_up(&ps->wait);}static void destroy_async (struct dev_state *ps, struct list_head *list){	struct async *as;	unsigned long flags;	spin_lock_irqsave(&ps->lock, flags);	while (!list_empty(list)) {		as = list_entry(list->next, struct async, asynclist);		list_del_init(&as->asynclist);		spin_unlock_irqrestore(&ps->lock, flags);                /* usb_unlink_urb calls the completion handler with status == -ENOENT */		usb_unlink_urb(as->urb);		spin_lock_irqsave(&ps->lock, flags);	}	spin_unlock_irqrestore(&ps->lock, flags);	as = async_getcompleted(ps);	while (as) {		free_async(as);		as = async_getcompleted(ps);	}}static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum){	struct list_head *p, *q, hitlist;	unsigned long flags;	INIT_LIST_HEAD(&hitlist);	spin_lock_irqsave(&ps->lock, flags);	list_for_each_safe(p, q, &ps->async_pending)		if (ifnum == list_entry(p, struct async, asynclist)->ifnum)			list_move_tail(p, &hitlist);	spin_unlock_irqrestore(&ps->lock, flags);	destroy_async(ps, &hitlist);}static inline void destroy_all_async(struct dev_state *ps){	        destroy_async(ps, &ps->async_pending);}/* * interface claims are made only at the request of user level code, * which can also release them (explicitly or by closing files). * they're also undone when devices disconnect. */static int driver_probe (struct usb_interface *intf,			 const struct usb_device_id *id){	return -ENODEV;}static void driver_disconnect(struct usb_interface *intf){	struct dev_state *ps = usb_get_intfdata (intf);	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;	if (!ps)		return;	/* NOTE:  this relies on usbcore having canceled and completed	 * all pending I/O requests; 2.6 does that.	 */	if (likely(ifnum < 8*sizeof(ps->ifclaimed)))		clear_bit(ifnum, &ps->ifclaimed);	else		warn("interface number %u out of range", ifnum);	usb_set_intfdata (intf, NULL);	/* force async requests to complete */	destroy_async_on_interface(ps, ifnum);}struct usb_driver usbdevfs_driver = {	.owner =	THIS_MODULE,	.name =		"usbfs",	.probe =	driver_probe,	.disconnect =	driver_disconnect,};static int claimintf(struct dev_state *ps, unsigned int ifnum){	struct usb_device *dev = ps->dev;	struct usb_interface *intf;	int err;	if (ifnum >= 8*sizeof(ps->ifclaimed))		return -EINVAL;	/* already claimed */	if (test_bit(ifnum, &ps->ifclaimed))		return 0;	/* lock against other changes to driver bindings */	down_write(&usb_bus_type.subsys.rwsem);	intf = usb_ifnum_to_if(dev, ifnum);	if (!intf)		err = -ENOENT;	else		err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps);	up_write(&usb_bus_type.subsys.rwsem);	if (err == 0)		set_bit(ifnum, &ps->ifclaimed);	return err;}static int releaseintf(struct dev_state *ps, unsigned int ifnum){	struct usb_device *dev;	struct usb_interface *intf;	int err;	err = -EINVAL;	if (ifnum >= 8*sizeof(ps->ifclaimed))		return err;	dev = ps->dev;	/* lock against other changes to driver bindings */	down_write(&usb_bus_type.subsys.rwsem);	intf = usb_ifnum_to_if(dev, ifnum);	if (!intf)		err = -ENOENT;	else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {		usb_driver_release_interface(&usbdevfs_driver, intf);		err = 0;	}	up_write(&usb_bus_type.subsys.rwsem);	return err;}static int checkintf(struct dev_state *ps, unsigned int ifnum){	if (ifnum >= 8*sizeof(ps->ifclaimed))		return -EINVAL;	if (test_bit(ifnum, &ps->ifclaimed))		return 0;	/* if not yet claimed, claim it for the driver */	dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",	       current->pid, current->comm, ifnum);	return claimintf(ps, ifnum);}static int findintfep(struct usb_device *dev, unsigned int ep){	unsigned int i, j, e;        struct usb_interface *intf;	struct usb_host_interface *alts;	struct usb_endpoint_descriptor *endpt;	if (ep & ~(USB_DIR_IN|0xf))		return -EINVAL;	if (!dev->actconfig)		return -ESRCH;	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {		intf = dev->actconfig->interface[i];		for (j = 0; j < intf->num_altsetting; j++) {                        alts = &intf->altsetting[j];			for (e = 0; e < alts->desc.bNumEndpoints; e++) {				endpt = &alts->endpoint[e].desc;				if (endpt->bEndpointAddress == ep)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -