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

📄 ohci-hcd-1.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * URB OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> *  * [ Initialisation is based on Linus'  ] * [ uhci code and gregs ohci fragments ] * [ (C) Copyright 1999 Linus Torvalds  ] * [ (C) Copyright 1999 Gregory P. Smith] *  *  * History: *  * v5.2 1999/12/07 URB 3rd preview,  * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi) * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume  * 	i386: HUB, Keyboard, Mouse, Printer  * * v4.3 1999/10/27 multiple HCs, bulk_request * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. * v4.0 1999/08/18  * v3.0 1999/06/25  * v2.1 1999/05/09  code clean up * v2.0 1999/05/04  * v1.0 1999/04/27 initial release *   */ #include <linux/config.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/malloc.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/timer.h>// #include <linux/spinlock.h>#include <linux/list.h>#include <linux/interrupt.h>  /* for in_interrupt() */#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#define DEBUG#include "usb.h"#include "ohci-hcd.h"#ifdef DEBUG	#define dbg printk#else	#define dbg __xxxstatic void __xxx (const char *format, ...) {}#endif#ifdef CONFIG_APM#include <linux/apm_bios.h>static int handle_apm_event (apm_event_t event);#endif#ifdef CONFIG_PMAC_PBOOK#include <linux/adb.h>#include <linux/pmu.h>#endifstatic DECLARE_WAIT_QUEUE_HEAD (op_wakeup); static LIST_HEAD (ohci_hcd_list);spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;/*-------------------------------------------------------------------------* * URB support functions  *-------------------------------------------------------------------------*/  /* free the private part of an URB */ static void urb_rm_priv (urb_t * urb) {	urb_priv_t * urb_priv = urb->hcpriv;	int i;	void * wait;		if (!urb_priv) return;		wait = urb_priv->wait;		for (i = 0; i < urb_priv->length; i++) {		if (urb_priv->td [i]) {			OHCI_FREE (urb_priv->td [i]);		}	}	kfree (urb->hcpriv);	urb->hcpriv = NULL;		if (wait) {		add_wait_queue (&op_wakeup, wait); 		wake_up (&op_wakeup);	}}/*-------------------------------------------------------------------------*/ #ifdef DEBUGstatic int sohci_get_current_frame_number (struct usb_device * dev);/* debug| print the main components of an URB      * small: 0) header + data packets 1) just header */ static void urb_print (urb_t * urb, char * str, int small){	unsigned int pipe= urb->pipe;	int i, len;		if (!urb->dev || !urb->dev->bus) {		printk(KERN_DEBUG " %s URB: no dev\n", str);		return;	}		printk (KERN_DEBUG "%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,"			"flags:%4x,len:%d/%d,stat:%d(%x)\n", 			str,		 	sohci_get_current_frame_number (urb->dev), 		 	usb_pipedevice (pipe),		 	usb_pipeendpoint (pipe), 		 	usb_pipeout (pipe)? 'O': 'I',		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"),		 	urb->transfer_flags, 		 	urb->actual_length, 		 	urb->transfer_buffer_length,		 	urb->status, urb->status);	if (!small) {		if (usb_pipecontrol (pipe)) {			printk (KERN_DEBUG " cmd(8):");			for (i = 0; i < 8 ; i++) 				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);			printk ("\n");		}		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {			printk (KERN_DEBUG " data(%d/%d):", 				urb->actual_length, 				urb->transfer_buffer_length);			len = usb_pipeout (pipe)? 						urb->transfer_buffer_length: urb->actual_length;			for (i = 0; i < 16 && i < len; i++) 				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);			printk ("%s stat:%d\n", i < len? "...": "", urb->status);		}	} 	}/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/void ep_print_int_eds (ohci_t * ohci, char * str) {	int i, j;	 __u32 * ed_p;	for (i= 0; i < 32; i++) {		j = 5;		printk (KERN_DEBUG " %s branch int %2d(%2x): ", str, i, i);		ed_p = &(ohci->hcca.int_table [i]);		while (*ed_p != 0 && j--) {			printk ("ed: %4x; ", (((ed_t *) bus_to_virt (*ed_p))->hwINFO));			ed_p = &(((ed_t *) bus_to_virt (*ed_p))->hwNextED);		}		printk ("\n");	}}		#endif/*-------------------------------------------------------------------------* * Interface functions (URB) *-------------------------------------------------------------------------*//* return a request to the completion handler */ static int sohci_return_urb (urb_t * urb){	urb_priv_t * urb_priv = urb->hcpriv;	urb_t * urbt;	unsigned int flags;	int i;		/* just to be sure */	if (!urb->complete) {		urb_rm_priv (urb);		usb_dec_dev_use (urb->dev);		return -1;	}		if (!urb_priv) return -1; /* urb already unlinked */	#ifdef DEBUG	urb_print (urb, "RET", usb_pipeout (urb->pipe));#endif	switch (usb_pipetype (urb->pipe)) {  		case PIPE_INTERRUPT:			urb->complete (urb); /* call complete and requeue URB */	  			urb->actual_length = 0;  			urb->status = USB_ST_URB_PENDING;  			if (urb_priv->state != URB_DEL)  				td_submit_urb (urb);  			break;  					case PIPE_ISOCHRONOUS:			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);			if (urbt) { /* send the reply and requeue URB */					urb->complete (urb);								spin_lock_irqsave (&usb_ed_lock, flags);				urb->actual_length = 0;  				urb->status = USB_ST_URB_PENDING;  				urb->start_frame = urb_priv->ed->last_iso + 1;  				if (urb_priv->state != URB_DEL) {  					for (i = 0; i < urb->number_of_packets; i++) {  						urb->iso_frame_desc[i].actual_length = 0;  						urb->iso_frame_desc[i].status = -EXDEV;  					}  					td_submit_urb (urb);  				}  				spin_unlock_irqrestore (&usb_ed_lock, flags);  				  			} else { /* unlink URB, call complete */				urb_rm_priv (urb);				usb_dec_dev_use (urb->dev);				urb->complete (urb); 				}					break;  						case PIPE_BULK:		case PIPE_CONTROL: /* unlink URB, call complete */			urb_rm_priv (urb);			usb_dec_dev_use (urb->dev);			urb->complete (urb);				break;	}	return 0;}/*-------------------------------------------------------------------------*//* get a transfer request */ static int sohci_submit_urb (urb_t * urb){	ohci_t * ohci;	ed_t * ed;	urb_priv_t * urb_priv;	unsigned int pipe = urb->pipe;	int i, size = 0;	unsigned int flags;		if (!urb->dev || !urb->dev->bus) return -EINVAL;		if (urb->hcpriv) return -EINVAL; /* urb already in use */	usb_inc_dev_use (urb->dev);	ohci = (ohci_t *) urb->dev->bus->hcpriv;	#ifdef DEBUG	urb_print (urb, "SUB", usb_pipein (pipe));#endif		if (usb_pipedevice (pipe) == ohci->rh.devnum) 		return rh_submit_urb (urb); /* a request to the virtual root hub */	/* every endpoint has a ed, locate and fill it */	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {		usb_dec_dev_use (urb->dev);			return -ENOMEM;	}	/* for the private part of the URB we need the number of TDs (size) */	switch (usb_pipetype (pipe)) {		case PIPE_BULK:	/* one TD for every 4096 Byte */			size = (urb->transfer_buffer_length - 1) / 4096 + 1;			break;		case PIPE_ISOCHRONOUS: /* number of packets from URB */			size = urb->number_of_packets;			for (i = 0; i < urb->number_of_packets; i++) {  				urb->iso_frame_desc[i].actual_length = 0;  				urb->iso_frame_desc[i].status = -EXDEV;  			}			break;		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */			size = (urb->transfer_buffer_length == 0)? 2: 						(urb->transfer_buffer_length - 1) / 4096 + 3;			break;		case PIPE_INTERRUPT: /* one TD */			size = 1;						break;	}	/* allocate the private part or the URB */	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);	if (!urb_priv) {		usb_dec_dev_use (urb->dev);			return -ENOMEM;	}	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));		/* fill the private part of the URB */	urb->hcpriv = urb_priv;	urb_priv->length = size;	urb_priv->td_cnt = 0;	urb_priv->state = 0;	urb_priv->ed = ed;		urb_priv->wait = NULL;		/* allocate the TDs */	for (i = 0; i < size; i++) { 		OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));		if (!urb_priv->td[i]) {			usb_dec_dev_use (urb->dev);				urb_rm_priv (urb);			return -ENOMEM;		}	}		spin_lock_irqsave (&usb_ed_lock, flags);		if (ed->state == ED_NEW || (ed->state & ED_DEL)) {		urb_rm_priv(urb);		usb_dec_dev_use (urb->dev);			return -EINVAL;	}		/* for ISOC transfers calculate start frame index */	if (urb->transfer_flags & USB_ISO_ASAP) { 		urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 								(ohci->hcca.frame_no + 10)) & 0xffff;	}			td_submit_urb (urb); /* fill the TDs and link it to the ed */							if (ed->state != ED_OPER)  /* link the ed into a chain if is not already */		ep_link (ohci, ed);	spin_unlock_irqrestore (&usb_ed_lock, flags);		urb->status = USB_ST_URB_PENDING; 	// queue_urb(s, &urb->urb_list);	return 0;	}/*-------------------------------------------------------------------------*//* deactivate all TDs and remove the private part of the URB */ static int sohci_unlink_urb (urb_t * urb){	unsigned int flags;	ohci_t * ohci;	DECLARE_WAITQUEUE (wait, current);		if (!urb) /* just to be sure */ 		return -EINVAL;		#ifdef DEBUG	urb_print (urb, "UNLINK", 1);#endif		  	ohci = (ohci_t *) urb->dev->bus->hcpriv; 	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) 		return rh_unlink_urb (urb); /* a request to the virtual root hub */		if (urb->hcpriv) { 		if (urb->status == USB_ST_URB_PENDING) { /* URB active? */			urb_priv_t  * urb_priv = urb->hcpriv;			urb_priv->state = URB_DEL; 			/* we want to delete the TDs of an URB from an ed 			 * request the deletion, it will be handled at the next USB-frame */			urb_priv->wait = &wait;						spin_lock_irqsave (&usb_ed_lock, flags);			ep_rm_ed (urb->dev, urb_priv->ed);			urb_priv->ed->state |= ED_URB_DEL;			spin_unlock_irqrestore (&usb_ed_lock, flags);			current->state = TASK_UNINTERRUPTIBLE;			schedule_timeout (HZ / 10); /* wait until all TDs are deleted */			remove_wait_queue (&op_wakeup, &wait); 		} else 			urb_rm_priv (urb);		usb_dec_dev_use (urb->dev);			}		return 0;}/*-------------------------------------------------------------------------*//* allocate private data space for a usb device */static int sohci_alloc_dev (struct usb_device *usb_dev){	struct ohci_device * dev;	dev = kmalloc (sizeof (*dev), GFP_KERNEL);	if (!dev)		return -ENOMEM;			memset (dev, 0, sizeof (*dev));	usb_dev->hcpriv = dev;	return 0;}/*-------------------------------------------------------------------------*//* free private data space of usb device */  static int sohci_free_dev (struct usb_device * usb_dev){	unsigned int flags;	int i, cnt = 0;	ed_t * ed;	DECLARE_WAITQUEUE (wait, current);	struct ohci_device * dev = usb_to_ohci (usb_dev);	ohci_t * ohci = usb_dev->bus->hcpriv;		if (!dev) return 0;		if (usb_dev->devnum >= 0) {			/* delete all TDs of all EDs */		spin_lock_irqsave (&usb_ed_lock, flags);			for(i = 0; i < NUM_EDS; i++) {  			ed = &(dev->ed[i]);  			if (ed->state != ED_NEW) {  				if (ed->state == ED_OPER) ep_unlink (ohci, ed);  				ep_rm_ed (usb_dev, ed);  				ed->state = ED_DEL;  				cnt++;  			}  		}  		spin_unlock_irqrestore (&usb_ed_lock, flags);  		    	if (cnt > 0) {     		dev->wait = &wait;			current->state = TASK_UNINTERRUPTIBLE;			schedule_timeout (HZ / 10);			remove_wait_queue (&op_wakeup, &wait);		}	}	kfree (dev);

⌨️ 快捷键说明

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