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

📄 devio.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *      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.11 2000/03/14 00:20:33 acher 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 <asm/uaccess.h>#include <linux/usb.h>#include "usbdevice_fs.h"struct async {        struct list_head asynclist;        struct dev_state *ps;	struct task_struct *task;	unsigned int signr;	void *userbuffer;        void *userurb;        urb_t urb;};/* * my own sync control and bulk methods. Here to experiment * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE. */struct sync {	wait_queue_head_t wait;};static void sync_completed(purb_t urb){        struct sync *s = (struct sync *)urb->context;         wake_up(&s->wait);	}static int do_sync(purb_t urb, int timeout){        DECLARE_WAITQUEUE(wait, current);	unsigned long tm;	signed long tmdiff;	struct sync s;	int ret;	tm = jiffies+timeout;	init_waitqueue_head(&s.wait);	add_wait_queue(&s.wait, &wait);	urb->context = &s;	urb->complete = sync_completed;	set_current_state(TASK_INTERRUPTIBLE);	if ((ret = usb_submit_urb(urb)))		goto out;	while (urb->status == -EINPROGRESS) {		tmdiff = tm - jiffies;		if (tmdiff <= 0) {			ret = -ETIMEDOUT;			goto out;		}		if (signal_pending(current)) {			ret = -EINTR;			goto out;		}		schedule_timeout(tmdiff);	}	ret = urb->status; out:	set_current_state(TASK_RUNNING);	usb_unlink_urb(urb);	remove_wait_queue(&s.wait, &wait);	return ret;}static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,			      __u16 value, __u16 index, void *data, __u16 size, int timeout){	urb_t *urb;	int ret;	if (!(urb = usb_alloc_urb(0)))		return -ENOMEM;	if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) {		usb_free_urb(urb);		return -ENOMEM;	}	urb->setup_packet[0] = requesttype;	urb->setup_packet[1] = request;	urb->setup_packet[2] = value;	urb->setup_packet[3] = value >> 8;	urb->setup_packet[4] = index;	urb->setup_packet[5] = index >> 8;	urb->setup_packet[6] = size;	urb->setup_packet[7] = size >> 8;	urb->dev = dev;        urb->pipe = pipe;        urb->transfer_buffer = data;        urb->transfer_buffer_length = size;	ret = do_sync(urb, timeout);	//if (ret >= 0)	//	ret = urb->status;	if (ret >= 0)		ret = urb->actual_length;	kfree(urb->setup_packet);	usb_free_urb(urb);	return ret;}static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, 			   void *data, int len, int *actual_length, int timeout){	urb_t *urb;	int ret;	if (!(urb = usb_alloc_urb(0)))		return -ENOMEM;        urb->dev = dev;        urb->pipe = pipe;        urb->transfer_buffer = data;        urb->transfer_buffer_length = len;	ret = do_sync(urb, timeout);	//if (ret >= 0)	//	ret = urb->status;	if (ret >= 0 && actual_length != NULL)		*actual_length = urb->actual_length;	usb_free_urb(urb);	return ret;}static long long usbdev_lseek(struct file *file, long long offset, int orig){	switch (orig) {	case 0:		file->f_pos = offset;		return file->f_pos;	case 1:		file->f_pos += offset;		return file->f_pos;	case 2:		return -EINVAL;	default:		return -EINVAL;	}}static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos){	struct dev_state *ps = (struct dev_state *)file->private_data;	ssize_t ret = 0;	unsigned len;	loff_t pos;	pos = *ppos;	down_read(&ps->devsem);	if (!ps->dev)		ret = -ENODEV;	else if (pos < 0)		ret = -EINVAL;	else 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 *)&ps->dev->descriptor) + pos, len))			ret = -EFAULT;		else {			*ppos += len;			buf += len;			nbytes -= len;			ret += len;		}	}	up_read(&ps->devsem);	return ret;}extern inline unsigned int ld2(unsigned int x){        unsigned int r = 0;                if (x >= 0x10000) {                x >>= 16;                r += 16;        }        if (x >= 0x100) {                x >>= 8;                r += 8;        }        if (x >= 0x10) {                x >>= 4;                r += 4;        }        if (x >= 4) {                x >>= 2;                r += 2;        }        if (x >= 2)                r++;        return r;}/* * async list handling */static struct async *alloc_async(unsigned int numisoframes){        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);        struct async *as = kmalloc(assize, GFP_KERNEL);        if (!as)                return NULL;        memset(as, 0, assize);        as->urb.number_of_packets = numisoframes;        return as;}static void free_async(struct async *as){        if (as->urb.transfer_buffer)                kfree(as->urb.transfer_buffer);        kfree(as);}extern __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);}extern __inline__ void async_removepending(struct async *as){        struct dev_state *ps = as->ps;        unsigned long flags;                spin_lock_irqsave(&ps->lock, flags);        list_del(&as->asynclist);        INIT_LIST_HEAD(&as->asynclist);        spin_unlock_irqrestore(&ps->lock, flags);}extern __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(&as->asynclist);                INIT_LIST_HEAD(&as->asynclist);        }        spin_unlock_irqrestore(&ps->lock, flags);        return as;}extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb){        unsigned long flags;        struct async *as;        struct list_head *p;        spin_lock_irqsave(&ps->lock, flags);        for (p = ps->async_pending.next; p != &ps->async_pending; ) {                as = list_entry(p, struct async, asynclist);                p = p->next;                if (as->userurb != userurb)                        continue;                list_del(&as->asynclist);                INIT_LIST_HEAD(&as->asynclist);                spin_unlock_irqrestore(&ps->lock, flags);                return as;        }        spin_unlock_irqrestore(&ps->lock, flags);        return NULL;}static void async_completed(purb_t urb){        struct async *as = (struct async *)urb->context;        struct dev_state *ps = as->ps;	struct siginfo sinfo;#if 0	printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", 	       urb->status, urb->error_count, urb->actual_length, urb->pipe);#endif        spin_lock(&ps->lock);        list_del(&as->asynclist);        list_add_tail(&as->asynclist, &ps->async_completed);        spin_unlock(&ps->lock);        wake_up(&ps->wait);	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);	}}static void destroy_all_async(struct dev_state *ps){        struct async *as;        unsigned long flags;        spin_lock_irqsave(&ps->lock, flags);        while (!list_empty(&ps->async_pending)) {                as = list_entry(ps->async_pending.next, struct async, asynclist);                list_del(&as->asynclist);                INIT_LIST_HEAD(&as->asynclist);                spin_unlock_irqrestore(&ps->lock, flags);                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */                usb_unlink_urb(&as->urb);                spin_lock_irqsave(&ps->lock, flags);        }        spin_unlock_irqrestore(&ps->lock, flags);        while ((as = async_getcompleted(ps)))                free_async(as);}/* * interface claiming */static void *driver_probe(struct usb_device *dev, unsigned int intf){	return NULL;}static void driver_disconnect(struct usb_device *dev, void *context){	struct dev_state *ps = (struct dev_state *)context;	ps->ifclaimed = 0;}struct usb_driver usbdevfs_driver = {	"usbdevfs",	driver_probe,	driver_disconnect,	LIST_HEAD_INIT(usbdevfs_driver.driver_list),	NULL,	0};static int claimintf(struct dev_state *ps, unsigned int intf){	struct usb_device *dev = ps->dev;	struct usb_interface *iface;	int err;	if (intf >= 8*sizeof(ps->ifclaimed) || !dev || intf >= dev->actconfig->bNumInterfaces)		return -EINVAL;	/* already claimed */	if (test_bit(intf, &ps->ifclaimed))		return 0;	iface = &dev->actconfig->interface[intf];	err = -EBUSY;	lock_kernel();	if (!usb_interface_claimed(iface)) {		usb_driver_claim_interface(&usbdevfs_driver, iface, ps);		set_bit(intf, &ps->ifclaimed);		err = 0;	}	unlock_kernel();	return err;}static int releaseintf(struct dev_state *ps, unsigned int intf){	struct usb_device *dev;	struct usb_interface *iface;	int err;	if (intf >= 8*sizeof(ps->ifclaimed))		return -EINVAL;	err = -EINVAL;	lock_kernel();	dev = ps->dev;	if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {		iface = &dev->actconfig->interface[intf];		usb_driver_release_interface(&usbdevfs_driver, iface);		err = 0;	}	unlock_kernel();	return err;}static int checkintf(struct dev_state *ps, unsigned int intf){	if (intf >= 8*sizeof(ps->ifclaimed))		return -EINVAL;	if (test_bit(intf, &ps->ifclaimed))		return 0;	/* if not yet claimed, claim it for the driver */	printk(KERN_WARNING "usbdevfs: process %d (%s) did not claim interface %u before use\n",	       current->pid, current->comm, intf);	return claimintf(ps, intf);}static int findintfep(struct usb_device *dev, unsigned int ep){	unsigned int i, j, e;        struct usb_interface *iface;	struct usb_interface_descriptor *alts;	struct usb_endpoint_descriptor *endpt;	if (ep & ~(USB_DIR_IN|0xf))		return -EINVAL;	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {		iface = &dev->actconfig->interface[i];		for (j = 0; j < iface->num_altsetting; j++) {                        alts = &iface->altsetting[j];			for (e = 0; e < alts->bNumEndpoints; e++) {				endpt = &alts->endpoint[e];				if (endpt->bEndpointAddress == ep)					return i;			}		}	}	return -ENOENT; }static int findintfif(struct usb_device *dev, unsigned int ifn){	unsigned int i, j;        struct usb_interface *iface;	struct usb_interface_descriptor *alts;	if (ifn & ~0xff)		return -EINVAL;	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {		iface = &dev->actconfig->interface[i];		for (j = 0; j < iface->num_altsetting; j++) {                        alts = &iface->altsetting[j];			if (alts->bInterfaceNumber == ifn)				return i;		}	}	return -ENOENT; }/* * file operations */static int usbdev_open(struct inode *inode, struct file *file){	struct usb_device *dev;	struct dev_state *ps;	int ret;	/* 	 * no locking necessary here, as both sys_open (actually filp_open)	 * and the hub thread have the kernel lock	 * (still acquire the kernel lock for safety)	 */	lock_kernel();	ret = -ENOENT;	if (ITYPE(inode->i_ino) != IDEVICE)		goto out;	dev = inode->u.usbdev_i.p.dev;	if (!dev)		goto out;	ret = -ENOMEM;	if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))		goto out;

⌨️ 快捷键说明

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