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

📄 hc_isp116x.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------* * isp1161 USB HCD for Linux Version 0.8 (9/3/2001) *  * Roman Weissgaerber weissg@vienna.at (C) 2001 * *-------------------------------------------------------------------------* * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *-------------------------------------------------------------------------*/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/list.h>#include <linux/ioport.h>#include <asm/io.h>#include <linux/usb.h>#include "hc_isp116x.h"static int hc_verbose = 1;static int hc_error_verbose = 0;static int urb_debug = 0;static int irq = 25;static unsigned long hcport = 0xf9080000;MODULE_PARM(hc_verbose,"i");MODULE_PARM_DESC(hc_verbose,"verbose startup messages, default is 1 (yes)");MODULE_PARM(hc_error_verbose,"i");MODULE_PARM_DESC(hc_error_verbose,"verbose error/warning messages, default is 0 (no)");MODULE_PARM(urb_debug,"i");MODULE_PARM_DESC(urb_debug,"debug urb messages, default is 0 (no)");MODULE_PARM(irq,"i");MODULE_PARM_DESC(irq,"IRQ 3, 10 (default)");MODULE_PARM(hcport,"i");MODULE_PARM_DESC(hcport,"ISP116x PORT 0x290");/*-------------------------------------------------------------------------* * Following from hc_simple.c Version 0.8 (9/3/2001) * Roman Weissgaerber weissg@vienna.at (C) 2001 *-------------------------------------------------------------------------*//* main lock for urb access */static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED; /*-------------------------------------------------------------------------*/ #ifdef CONFIG_ARCTIC2  /* MVL-CEE */#include <linux/device.h>static int hc_isp_suspend(struct device * dev, u32 state, u32 level);static int hc_isp_resume(struct device * dev, u32 level);static int hc_isp_scale(struct bus_op_point * op, u32 level);static struct device_driver hc_isp_driver_ldm = {       name:      	"USB_PH_ISP1161",       devclass:  	NULL,       probe:     	NULL,       suspend:   	hc_isp_suspend,       resume:    	hc_isp_resume,       scale:	  	hc_isp_scale,       remove:    	NULL,       constraints:	NULL,};static struct device hc_isp_device_ldm = {       name:		"Philips ISP1161 USB ",       bus_id:		"hc_isp",       driver: 		NULL,       power_state:	DPM_POWER_OFF,};static void hc_isp_ldm_register(void){	extern void ebc_driver_register(struct device_driver *driver);	extern void ebc_device_register(struct device *device);	ebc_driver_register(&hc_isp_driver_ldm);	ebc_device_register(&hc_isp_device_ldm);}static void hc_isp_ldm_unregister(void){	extern void ebc_driver_unregister(struct device_driver *driver);	extern void ebc_device_unregister(struct device *device);	ebc_driver_unregister(&hc_isp_driver_ldm);	ebc_device_unregister(&hc_isp_device_ldm);}static int hc_isp_scale(struct bus_op_point * op, u32 level){	/* linux-pm-TODO */	return 0;}/* * TODO: get rid of pm_hci. */static hci_t *pm_hci = NULL;static int hc_reset (hci_t * hci);static int hc_start (hci_t * hci);static int hc_alloc_trans_buffer (hci_t * hci);static void hc_isp116x_intregdump(hci_t * hci){       printk("HcInterruptStatus=%x HcInterruptEnable=%x\n", READ_REG32 (hci, HcInterruptStatus), READ_REG32 (hci, HcInterruptEnable));       printk("HcuPInterrupt=%x HcuPInterruptEnable=%x\n", READ_REG16 (hci, HcuPInterrupt), READ_REG16 (hci, HcuPInterruptEnable));       printk("HcHardwareConfiguration=%x\n", READ_REG16 (hci,HcHardwareConfiguration)); }static int hc_isp_suspend(struct device * dev, u32 state, u32 level){  switch(level)  {      case SUSPEND_POWER_DOWN:       WRITE_REG16 (pm_hci, 0, HcDMAConfiguration);       WRITE_REG16 (pm_hci, 0, HcuPInterruptEnable);       WRITE_REG16(pm_hci, READ_REG16(pm_hci, HcHardwareConfiguration) & 		   ~InterruptPinEnable, HcHardwareConfiguration);       hc_release_hci(pm_hci);       break;  }    return 0;}static int hc_isp_resume(struct device * dev, u32 level){  switch(level)  {     case RESUME_POWER_ON:		/*		 * Turn off sleep mode.		 */       hc_found_hci(hcport, irq, 0);         break;  }  return 0;}#endif /* MVL-CEE *//*-------------------------------------------------------------------------*/ /* URB HCD API function layer * * * *//*-------------------------------------------------------------------------*/ /* set actual length to 0 and set status  * queue URB * */ static inline int hcs_urb_queue (hci_t * hci, struct urb * urb){	int i;		if (usb_pipeisoc (urb->pipe)) {		for (i = 0; i < urb->number_of_packets; i++) {  			urb->iso_frame_desc[i].actual_length = 0;  			urb->iso_frame_desc[i].status = -EXDEV;  		}	}		urb->status = USB_ST_URB_PENDING;	urb->actual_length = 0;	urb->error_count = 0;	qu_queue_urb (hci, urb);	return 0;}/*-------------------------------------------------------------------------*//* return path (complete - callback) of URB API * also handles resubmition of intr URBs  * */static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok){		struct usb_device * dev = urb->dev;	int resubmit = 0;	if (urb_debug)		urb_print (urb, "RET", usb_pipeout (urb->pipe));	  	resubmit = urb->interval && resub_ok; 		urb->dev = urb->hcpriv = NULL;	if (urb->complete) 		urb->complete (urb); /* call complete */		if (resubmit) { /* requeue the URB */		urb->dev = dev;				hcs_urb_queue (hci, urb);	}	return 0;}/*-------------------------------------------------------------------------*//* got a transfer request  * */ static int hci_submit_urb (struct urb * urb){	hci_t * hci;	unsigned int pipe = urb->pipe;	unsigned long flags;	int ret;	if (!urb->dev || !urb->dev->bus || urb->hcpriv) 		return -EINVAL;	if (usb_endpoint_halted (urb->dev, 				usb_pipeendpoint (pipe), usb_pipeout (pipe))) 		return -EPIPE;		hci = (hci_t *) urb->dev->bus->hcpriv;		/* a request to the virtual root hub */	if (usb_pipedevice (pipe) == hci->rh.devnum) {		return rh_submit_urb (urb);		}	if (urb_debug)		urb_print (urb, "SUB", usb_pipein (pipe));	/* queue the URB to its endpoint-queue */	 	spin_lock_irqsave (&usb_urb_lock, flags);		ret = hcs_urb_queue (hci, urb);	spin_unlock_irqrestore (&usb_urb_lock, flags);	return ret;}/*-------------------------------------------------------------------------*//* unlink URB: mark the URB to unlink   * */ static int hci_unlink_urb (struct urb * urb){	unsigned long flags;	hci_t * hci;	DECLARE_WAITQUEUE (wait, current);	void * comp = NULL;		if (!urb) /* just to be sure */ 		return -EINVAL;			if (!urb->dev || !urb->dev->bus)		return -ENODEV;	hci = (hci_t *) urb->dev->bus->hcpriv; 	/* a request to the virtual root hub */	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {		return rh_unlink_urb (urb); 	}	if (urb_debug)		urb_print (urb, "UNLINK", 1);			spin_lock_irqsave (&usb_urb_lock, flags);	/* HACK: It seems the HID driver sometimes tries to unlink	 * URBs which have never been submitted - and hence whose	 * urb_list field has never been initialized.  This causes	 * crashes on unplug */	if ( (urb->urb_list.prev &&  urb->urb_list.next)	     && !list_empty (&urb->urb_list)) { /* URB active? */			if (urb->transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) { 			/* asynchron with callback */					list_del (&urb->urb_list); /* relink the urb to the del list */			list_add (&urb->urb_list, &hci->del_list);			comp = urb->complete;			urb->complete = NULL;			spin_unlock_irqrestore (&usb_urb_lock, flags);		} else { /* synchron without callback */						add_wait_queue (&hci->waitq, &wait);	  			set_current_state (TASK_UNINTERRUPTIBLE);			list_del (&urb->urb_list); /* relink the urb to the del list */			list_add (&urb->urb_list, &hci->del_list);			spin_unlock_irqrestore (&usb_urb_lock, flags);						schedule_timeout(HZ/50);						if (!list_empty (&urb->urb_list))				list_del (&urb->urb_list);			urb->complete = comp;			urb->hcpriv = NULL;			remove_wait_queue (&hci->waitq, &wait); 		}	} else { /* hcd does not own URB but we keep the driver happy anyway */		spin_unlock_irqrestore (&usb_urb_lock, flags);				if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {				urb->status = -ENOENT;			urb->actual_length = 0;					urb->complete (urb); 			urb->status = 0;			} else {			urb->status = -ENOENT;		}		}		return 0;}/*-------------------------------------------------------------------------*//* allocate private data space for a usb device  * */static int hci_alloc_dev (struct usb_device * usb_dev){	struct hci_device * dev;	int i;		dev = kmalloc (sizeof (*dev), GFP_KERNEL);	if (!dev)		return -ENOMEM;			memset (dev, 0, sizeof (*dev));	for (i = 0; i < 32; i++) {		INIT_LIST_HEAD (&(dev->urb_queue [i]));		dev->pipe_head [i] = NULL;	}			usb_dev->hcpriv = dev;		if (hc_verbose)		printk ("USB HC dev alloc %d bytes\n", sizeof (*dev));			return 0;}/*-------------------------------------------------------------------------*//* free private data space of usb device  * */  static int hci_free_dev (struct usb_device * usb_dev){	if (hc_verbose)		printk ("USB HC dev free\n");			if (usb_dev->hcpriv)		kfree (usb_dev->hcpriv);	usb_dev->hcpriv = NULL;	return 0;}/*-------------------------------------------------------------------------*//* tell us the current USB frame number  * */static int hci_get_current_frame_number (struct usb_device *usb_dev) {	hci_t * hci = usb_dev->bus->hcpriv;	int frame_no;		frame_no =  GET_FRAME_NUMBER (hci);	return frame_no;}/*-------------------------------------------------------------------------*//* make a list of all io-functions  * */ static struct usb_operations hci_device_operations = {	hci_alloc_dev,	hci_free_dev,	hci_get_current_frame_number,	hci_submit_urb,	hci_unlink_urb};/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*//* URB queueing: *  * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of  * active URBs. * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list) * For every endpoint the head URB of the queued URBs is linked to one of  * those lists. *  * The rest of the queued URBs of an endpoint are linked into a  * private URB list for each endpoint. (hci_dev->urb_queue [endpoint_io]) * hci_dev->pipe_head [endpoint_io] .. points to the head URB which is  * in one of the active URB lists. *  * The index of an endpoint consists of its number and its direction. *  * The state of an intr and iso URB is 0.  * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet) *  * * * */ static inline int qu_pipeindex (__u32 pipe) {	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 				0 : usb_pipeout (pipe));}static inline void qu_seturbstate (struct urb * urb, int state) {	urb->pipe &= ~0x3;	urb->pipe |= state & 0x3;}static inline int qu_urbstate (struct urb * urb) {	return urb->pipe & 0x3;}/*-------------------------------------------------------------------------*/	static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb) {	int urb_state = 0;	switch (usb_pipetype (urb->pipe)) {		case PIPE_CONTROL:			list_add (&urb->urb_list, &hci->ctrl_list);			urb_state = US_CTRL_SETUP;			break;				case PIPE_BULK:			list_add (&urb->urb_list, &hci->bulk_list);			if (urb->transfer_flags & USB_ZERO_PACKET)				urb_state = US_BULK0;			break;				case PIPE_INTERRUPT:			urb->start_frame = (hci->frame_no + urb->interval) & 0x7ff;			list_add (&urb->urb_list, &hci->intr_list);			break;				case PIPE_ISOCHRONOUS:			list_add (&urb->urb_list, &hci->iso_list);			break;	}	qu_seturbstate (urb, urb_state);}static int qu_queue_urb (hci_t * hci, struct urb * urb){	int index = qu_pipeindex (urb->pipe);	struct hci_device * hci_dev = usb_to_hci (urb->dev);	if (hci_dev->pipe_head [index]) {		__list_add (&urb->urb_list, 				hci_dev->urb_queue [index].prev, &(hci_dev->urb_queue [index]));	 } else {	 	hci_dev->pipe_head [index] = urb;		qu_queue_active_urb (hci, urb);	}	return 0;}/*-------------------------------------------------------------------------*//* return path (after transfer) * remove URB from queue and return it to the api layer * */static void qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok) {		struct hci_device * hci_dev = usb_to_hci (urb->dev);	int index = qu_pipeindex (urb->pipe);		list_del (&urb->urb_list);	INIT_LIST_HEAD (&urb->urb_list);			if (!list_empty (&(hci_dev->urb_queue [index]))) {		urb = list_entry (hci_dev->urb_queue [index].next, struct urb, urb_list);		list_del (&urb->urb_list);		INIT_LIST_HEAD (&urb->urb_list);		hci_dev->pipe_head [index] = urb;		qu_queue_active_urb (hci, urb);	} else {		hci_dev->pipe_head [index] = NULL;	}		hcs_return_urb (hci, urb, resub_ok);	}/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*//* SCHEDULE operations *  * * * */static int sh_scan_urb_list (hci_t * hci, struct list_head * list_lh) {	struct list_head * lh;	struct urb * urb;	list_for_each (lh, list_lh) {		urb = list_entry (lh, struct urb, urb_list);		if (!usb_pipeint (urb->pipe) ||			(((hci->frame_no - urb->start_frame) & 0x7ff) >= urb->interval)) {				if (!sh_add_packet (hci, urb))					return 0;				else					urb->start_frame = hci->frame_no;		}	}	return 1;}/*-------------------------------------------------------------------------*//* scan lists of active URBs and construct a schedule for a frame * */static int sh_schedule_trans (hci_t * hci){	int units_left;	hci->trans = 0;			units_left = sh_scan_urb_list (hci, &hci->intr_list);	if (units_left) {  /* add CTRL transfers */		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);	} 		if (units_left) {  /* add BULK transfers */		sh_scan_urb_list (hci, &hci->bulk_list);	}	return 0;}/*-------------------------------------------------------------------------*//* add some parts of the active URB to the schedule * */static int sh_add_packet (hci_t * hci, struct urb * urb){	__u8 * data = NULL;	int len = 0;	int toggle = 0;

⌨️ 快捷键说明

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