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

📄 ezusb.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *	ezusb.c  --  Firmware download miscdevice for Anchorchips EZUSB microcontrollers. * *	Copyright (C) 1999 *          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. * *  History: *   0.1  26.05.99  Created *   0.2  23.07.99  Removed EZUSB_INTERRUPT. Interrupt pipes may be polled with *                  bulk reads. *                  Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK. *                  Preliminary ISO support *   0.3  01.09.99  Async Bulk and ISO support *   0.4  01.09.99  Set callback_frames to the total number of frames to make *                  it work with OHCI-HCD *        03.12.99  Now that USB error codes are negative, return them to application *                  instead of ENXIO *  $Id: ezusb.c,v 1.24 2000/01/09 12:19:42 fliegl Exp $ *//*****************************************************************************/#include <linux/version.h>#include <linux/module.h>#include <linux/socket.h>#include <linux/miscdevice.h>#include <linux/list.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <asm/uaccess.h>//#include <linux/spinlock.h>#include "usb.h"#include "ezusb.h"/* --------------------------------------------------------------------- */#define NREZUSB 1static struct ezusb {	struct semaphore mutex;	struct usb_device *usbdev;	struct list_head async_pending;	struct list_head async_completed;	wait_queue_head_t wait;	spinlock_t lock;} ezusb[NREZUSB];struct async {	struct list_head asynclist;	struct ezusb *ez;	void *userdata;	unsigned datalen;	void *context;	urb_t urb;};/*-------------------------------------------------------------------*/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 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;}#if 0/* why doesn't this work properly on i386? */extern inline unsigned int ld2(unsigned int x){	unsigned int r;	__asm__("bsrl %1,%0" : "=r" (r) : "g" (x));	return r;}#endif/* --------------------------------------------------------------------- */extern __inline__ void async_removelist(struct async *as){	struct ezusb *ez = as->ez;	unsigned long flags;	spin_lock_irqsave(&ez->lock, flags);	list_del(&as->asynclist);	INIT_LIST_HEAD(&as->asynclist);	spin_unlock_irqrestore(&ez->lock, flags);}extern __inline__ void async_newpending(struct async *as){	struct ezusb *ez = as->ez;	unsigned long flags;		spin_lock_irqsave(&ez->lock, flags);	list_add_tail(&as->asynclist, &ez->async_pending);	spin_unlock_irqrestore(&ez->lock, flags);}extern __inline__ void async_removepending(struct async *as){	struct ezusb *ez = as->ez;	unsigned long flags;		spin_lock_irqsave(&ez->lock, flags);	list_del(&as->asynclist);	INIT_LIST_HEAD(&as->asynclist);	spin_unlock_irqrestore(&ez->lock, flags);}extern __inline__ struct async *async_getcompleted(struct ezusb *ez){	unsigned long flags;	struct async *as = NULL;	spin_lock_irqsave(&ez->lock, flags);	if (!list_empty(&ez->async_completed)) {		as = list_entry(ez->async_completed.next, struct async, asynclist);		list_del(&as->asynclist);		INIT_LIST_HEAD(&as->asynclist);	}	spin_unlock_irqrestore(&ez->lock, flags);	return as;}extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context){	unsigned long flags;	struct async *as;	struct list_head *p;	spin_lock_irqsave(&ez->lock, flags);	for (p = ez->async_pending.next; p != &ez->async_pending; ) {		as = list_entry(p, struct async, asynclist);		p = p->next;		if (as->context != context)			continue;		list_del(&as->asynclist);		INIT_LIST_HEAD(&as->asynclist);		spin_unlock_irqrestore(&ez->lock, flags);		return as;	}	spin_unlock_irqrestore(&ez->lock, flags);	return NULL;}/* --------------------------------------------------------------------- */static void async_completed(purb_t urb){	struct async *as = (struct async *)urb->context;	struct ezusb *ez = as->ez;	unsigned cnt;printk(KERN_DEBUG "ezusb: async_completed: status %d errcount %d actlen %d pipe 0x%x\n",        urb->status, urb->error_count, urb->actual_length, urb->pipe);	spin_lock(&ez->lock);	list_del(&as->asynclist);	list_add_tail(&as->asynclist, &ez->async_completed);	spin_unlock(&ez->lock);	wake_up(&ez->wait);}static void destroy_all_async(struct ezusb *ez){	struct async *as;	unsigned long flags;	spin_lock_irqsave(&ez->lock, flags);	if (!list_empty(&ez->async_pending)) {		as = list_entry(ez->async_pending.next, struct async, asynclist);		list_del(&as->asynclist);		INIT_LIST_HEAD(&as->asynclist);		spin_unlock_irqrestore(&ez->lock, flags);		/* discard_urb calls the completion handler with status == USB_ST_URB_KILLED */		usb_unlink_urb(&as->urb);		spin_lock_irqsave(&ez->lock, flags);	}	spin_unlock_irqrestore(&ez->lock, flags);	while ((as = async_getcompleted(ez)))		free_async(as);}/* --------------------------------------------------------------------- */static loff_t ezusb_llseek(struct file *file, loff_t offset, int origin){	struct ezusb *ez = (struct ezusb *)file->private_data;	switch(origin) {	case 1:		offset += file->f_pos;		break;	case 2:		offset += 0x10000;		break;	}	if (offset < 0 || offset >= 0x10000)		return -EINVAL;	return (file->f_pos = offset);}static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos){	struct ezusb *ez = (struct ezusb *)file->private_data;	unsigned pos = *ppos;	unsigned ret = 0;	unsigned len;	unsigned char b[64];	int i;	if (*ppos < 0 || *ppos >= 0x10000)		return -EINVAL;	down(&ez->mutex);	if (!ez->usbdev) {		up(&ez->mutex);		return -EIO;	}	while (sz > 0 && pos < 0x10000) {		len = sz;		if (len > sizeof(b))			len = sizeof(b);		if (pos + len > 0x10000)			len = 0x10000 - pos;		i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ);		if (i < 0) {			up(&ez->mutex);			printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i);			*ppos = pos;			if (ret)				return ret;			return i;		}		if (copy_to_user(buf, b, len)) {			up(&ez->mutex);			*ppos = pos;			if (ret)				return ret;			return -EFAULT;		}		pos += len;		buf += len;		sz -= len;		ret += len;	}	up(&ez->mutex);	*ppos = pos;	return ret;}static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t *ppos){	struct ezusb *ez = (struct ezusb *)file->private_data;	unsigned pos = *ppos;	unsigned ret = 0;	unsigned len;	unsigned char b[64];	int i;	if (*ppos < 0 || *ppos >= 0x10000)		return -EINVAL;	down(&ez->mutex);	if (!ez->usbdev) {		up(&ez->mutex);		return -EIO;	}	while (sz > 0 && pos < 0x10000) {		len = sz;		if (len > sizeof(b))			len = sizeof(b);		if (pos + len > 0x10000)			len = 0x10000 - pos;		if (copy_from_user(b, buf, len)) {			up(&ez->mutex);			*ppos = pos;			if (ret)				return ret;			return -EFAULT;		}		printk("writemem: %d %p %d\n",pos,b,len);		i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ);		if (i < 0) {			up(&ez->mutex);			printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i);			*ppos = pos;			if (ret)				return ret;			return i;		}		pos += len;		buf += len;		sz -= len;		ret += len;	}	up(&ez->mutex);	*ppos = pos;	return ret;}static int ezusb_open(struct inode *inode, struct file *file){	struct ezusb *ez = &ezusb[0];	down(&ez->mutex);	while (!ez->usbdev) {		up(&ez->mutex);		if (!(file->f_flags & O_NONBLOCK)) {			return -EIO;		}		schedule_timeout(HZ/2);		if (signal_pending(current))			return -EAGAIN;		down(&ez->mutex);	}	up(&ez->mutex);	file->f_pos = 0;	file->private_data = ez;	MOD_INC_USE_COUNT;	return 0;}static int ezusb_release(struct inode *inode, struct file *file){	struct ezusb *ez = (struct ezusb *)file->private_data;	down(&ez->mutex);	destroy_all_async(ez);	up(&ez->mutex);	MOD_DEC_USE_COUNT;	return 0;}static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,			 unsigned char request, unsigned short value, 			 unsigned short index, unsigned short length,			 unsigned int timeout, void *data){	unsigned char *tbuf = NULL;	unsigned int pipe;	int i;	if (length > PAGE_SIZE)		return -EINVAL;	/* __range_ok is broken; 	   with unsigned short size, it gave	   addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx	*/	if (requesttype & 0x80) {		pipe = usb_rcvctrlpipe(usbdev, 0);		if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length))			return -EFAULT;	} else		pipe = usb_sndctrlpipe(usbdev, 0);	if (length > 0) {		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))			return -ENOMEM;		if (!(requesttype & 0x80)) {			if (copy_from_user(tbuf, data, length)) {				free_page((unsigned long)tbuf);				return -EFAULT;			}		}	}	i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length, timeout);	if (i < 0) {		if (length > 0)			free_page((unsigned long)tbuf);		printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 		       requesttype, request, length, i);		return i;	}	if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length))		i = -EFAULT;	if (length > 0)		free_page((unsigned long)tbuf);	return i;}static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data){	unsigned char *tbuf = NULL;	unsigned int pipe;	int len2 = 0;	int ret = 0;	if (length > PAGE_SIZE)		return -EINVAL;	if ((ep & ~0x80) >= 16)		return -EINVAL;	if (ep & 0x80) {		pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f);		if (length > 0 && !access_ok(VERIFY_WRITE, data, length))			return -EFAULT;	} else		pipe = usb_sndbulkpipe(usbdev, ep & 0x7f);	if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80)))		return -EINVAL;	if (length > 0) {		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))			return -ENOMEM;		if (!(ep & 0x80)) {			if (copy_from_user(tbuf, data, length)) {				free_page((unsigned long)tbuf);				return -EFAULT;			}		}	}	ret = usb_bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout);	if (ret < 0) {		if (length > 0)			free_page((unsigned long)tbuf);		printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 		       ep, length, ret);		return -ENXIO;	}	if (len2 > length)		len2 = length;	ret = len2;	if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2))		ret = -EFAULT;	if (length > 0)		free_page((unsigned long)tbuf);	return ret;}static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep){	if ((ep & ~0x80) >= 16)		return -EINVAL;	usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0);	return 0;}static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting){	if (usb_set_interface(usbdev, interface, altsetting) < 0)		return -EINVAL;	return 0;}static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config){	if (usb_set_configuration(usbdev, config) < 0)		return -EINVAL;	return 0;}#define usb_sndintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))#define usb_rcvintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)char* stuff[512];static void int_compl(purb_t purb){  printk("INT_COMPL\n");  }static int ezusb_interrupt(struct ezusb *ez, struct ezusb_interrupt *ab){  urb_t *urb;  unsigned int pipe;  urb=(urb_t*)kmalloc(sizeof(urb_t),GFP_KERNEL);  if (!urb)  {    return -ENOMEM;  }  memset(urb,0,sizeof(urb_t));     if ((ab->ep & ~0x80) >= 16)    return -EINVAL;  if (ab->ep & 0x80)     {      pipe = usb_rcvintpipe(ez->usbdev, ab->ep & 0x7f);      if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len))	return -EFAULT;    }   else    pipe = usb_sndintpipe(ez->usbdev, ab->ep & 0x7f);    memcpy(stuff,ab->data,64);  urb->transfer_buffer=stuff;  urb->transfer_buffer_length=ab->len;  urb->complete=int_compl;  urb->pipe=pipe;  urb->dev=ez->usbdev;  urb->interval=ab->interval;  return usb_submit_urb(urb);}static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab){

⌨️ 快捷键说明

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