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

📄 uhci.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	case RH_GET_STATUS | RH_ENDPOINT:		*(__u16 *)data = cpu_to_le16(0);		OK(2);	case RH_GET_STATUS | RH_CLASS:		*(__u32 *)data = cpu_to_le32(0);		OK(4);		/* hub power */	case RH_GET_STATUS | RH_OTHER | RH_CLASS:		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |			((status & USBPORTSC_PEC) >> (3 - 1)) |			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));			status = (status & USBPORTSC_CCS) |			((status & USBPORTSC_PE) >> (2 - 1)) |			((status & USBPORTSC_SUSP) >> (12 - 2)) |			((status & USBPORTSC_PR) >> (9 - 4)) |			(1 << 8) |      /* power on */			((status & USBPORTSC_LSDA) << (-8 + 9));		*(__u16 *)data = cpu_to_le16(status);		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);		OK(4);	case RH_CLEAR_FEATURE | RH_ENDPOINT:		switch (wValue) {		case RH_ENDPOINT_STALL:			OK(0);		}		break;	case RH_CLEAR_FEATURE | RH_CLASS:		switch (wValue) {		case RH_C_HUB_OVER_CURRENT:			OK(0);	/* hub power over current */		}		break;	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:		switch (wValue) {		case RH_PORT_ENABLE:			CLR_RH_PORTSTAT(USBPORTSC_PE);			OK(0);		case RH_PORT_SUSPEND:			CLR_RH_PORTSTAT(USBPORTSC_SUSP);			OK(0);		case RH_PORT_POWER:			OK(0);	/* port power */		case RH_C_PORT_CONNECTION:			SET_RH_PORTSTAT(USBPORTSC_CSC);			OK(0);		case RH_C_PORT_ENABLE:			SET_RH_PORTSTAT(USBPORTSC_PEC);			OK(0);		case RH_C_PORT_SUSPEND:			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */			OK(0);		case RH_C_PORT_OVER_CURRENT:			OK(0);	/* port power over current */		case RH_C_PORT_RESET:			uhci->rh.c_p_r[wIndex - 1] = 0;			OK(0);		}		break;	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:		switch (wValue) {		case RH_PORT_SUSPEND:			SET_RH_PORTSTAT(USBPORTSC_SUSP);			OK(0);		case RH_PORT_RESET:			SET_RH_PORTSTAT(USBPORTSC_PR);			mdelay(50);	/* USB v1.1 7.1.7.3 */			uhci->rh.c_p_r[wIndex - 1] = 1;			CLR_RH_PORTSTAT(USBPORTSC_PR);			udelay(10);			SET_RH_PORTSTAT(USBPORTSC_PE);			mdelay(10);			SET_RH_PORTSTAT(0xa);			OK(0);		case RH_PORT_POWER:			OK(0); /* port power ** */		case RH_PORT_ENABLE:			SET_RH_PORTSTAT(USBPORTSC_PE);			OK(0);		}		break;	case RH_SET_ADDRESS:		uhci->rh.devnum = wValue;		OK(0);	case RH_GET_DESCRIPTOR:		switch ((wValue & 0xff00) >> 8) {		case 0x01:	/* device descriptor */			len = min_t(unsigned int, leni,				  min_t(unsigned int,				      sizeof(root_hub_dev_des), wLength));			memcpy(data, root_hub_dev_des, len);			OK(len);		case 0x02:	/* configuration descriptor */			len = min_t(unsigned int, leni,				  min_t(unsigned int,				      sizeof(root_hub_config_des), wLength));			memcpy (data, root_hub_config_des, len);			OK(len);		case 0x03:	/* string descriptors */			len = usb_root_hub_string (wValue & 0xff,				uhci->io_addr, "UHCI-alt",				data, wLength);			if (len > 0) {				OK(min_t(int, leni, len));			} else 				stat = -EPIPE;		}		break;	case RH_GET_DESCRIPTOR | RH_CLASS:		root_hub_hub_des[2] = uhci->rh.numports;		len = min_t(unsigned int, leni,			  min_t(unsigned int, sizeof(root_hub_hub_des), wLength));		memcpy(data, root_hub_hub_des, len);		OK(len);	case RH_GET_CONFIGURATION:		*(__u8 *)data = 0x01;		OK(1);	case RH_SET_CONFIGURATION:		OK(0);	case RH_GET_INTERFACE | RH_INTERFACE:		*(__u8 *)data = 0x00;		OK(1);	case RH_SET_INTERFACE | RH_INTERFACE:		OK(0);	default:		stat = -EPIPE;	}	urb->actual_length = len;	return stat;}/* * MUST be called with urb->lock acquired */static int rh_unlink_urb(struct urb *urb){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	if (uhci->rh.urb == urb) {		urb->status = -ENOENT;		uhci->rh.send = 0;		uhci->rh.urb = NULL;		del_timer(&uhci->rh.rh_int_timer);	}	return 0;}static void uhci_free_pending_qhs(struct uhci *uhci){	struct list_head *tmp, *head;	unsigned long flags;	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);	head = &uhci->qh_remove_list;	tmp = head->next;	while (tmp != head) {		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);		tmp = tmp->next;		list_del_init(&qh->remove_list);		uhci_free_qh(uhci, qh);	}	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);}static void uhci_call_completion(struct urb *urb){	struct urb_priv *urbp;	struct usb_device *dev = urb->dev;	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;	int is_ring = 0, killed, resubmit_interrupt, status;	struct urb *nurb;	unsigned long flags;	spin_lock_irqsave(&urb->lock, flags);	urbp = (struct urb_priv *)urb->hcpriv;	if (!urbp || !urb->dev) {		spin_unlock_irqrestore(&urb->lock, flags);		return;	}	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||			urb->status == -ECONNRESET);	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&			urb->interval);	nurb = urb->next;	if (nurb && !killed) {		int count = 0;		while (nurb && nurb != urb && count < MAX_URB_LOOP) {			if (nurb->status == -ENOENT ||			    nurb->status == -ECONNABORTED ||			    nurb->status == -ECONNRESET) {				killed = 1;				break;			}			nurb = nurb->next;			count++;		}		if (count == MAX_URB_LOOP)			err("uhci_call_completion: too many linked URB's, loop? (first loop)");		/* Check to see if chain is a ring */		is_ring = (nurb == urb);	}	if (urbp->transfer_buffer_dma_handle)		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);	if (urbp->setup_packet_dma_handle)		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);	status = urbp->status;	if (!resubmit_interrupt || killed)		/* We don't need urb_priv anymore */		uhci_destroy_urb_priv(urb);	if (!killed)		urb->status = status;	urb->dev = NULL;	spin_unlock_irqrestore(&urb->lock, flags);	if (urb->complete)		urb->complete(urb);	if (resubmit_interrupt)		/* Recheck the status. The completion handler may have */		/*  unlinked the resubmitting interrupt URB */		killed = (urb->status == -ENOENT ||			  urb->status == -ECONNABORTED ||			  urb->status == -ECONNRESET);	if (resubmit_interrupt && !killed) {		urb->dev = dev;		uhci_reset_interrupt(urb);	} else {		if (is_ring && !killed) {			urb->dev = dev;			uhci_submit_urb(urb);		} else {			/* We decrement the usage count after we're done */			/*  with everything */			usb_dec_dev_use(dev);		}	}}static void uhci_finish_completion(struct uhci *uhci){	struct list_head *tmp, *head;	unsigned long flags;	spin_lock_irqsave(&uhci->complete_list_lock, flags);	head = &uhci->complete_list;	tmp = head->next;	while (tmp != head) {		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);		struct urb *urb = urbp->urb;		list_del_init(&urbp->complete_list);		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);		uhci_call_completion(urb);		spin_lock_irqsave(&uhci->complete_list_lock, flags);		head = &uhci->complete_list;		tmp = head->next;	}	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);}static void uhci_remove_pending_qhs(struct uhci *uhci){	struct list_head *tmp, *head;	unsigned long flags;	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);	head = &uhci->urb_remove_list;	tmp = head->next;	while (tmp != head) {		struct urb *urb = list_entry(tmp, struct urb, urb_list);		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;		tmp = tmp->next;		list_del_init(&urb->urb_list);		urbp->status = urb->status = -ECONNRESET;		uhci_add_complete(urb);	}	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);}static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs){	struct uhci *uhci = __uhci;	unsigned int io_addr = uhci->io_addr;	unsigned short status;	struct list_head *tmp, *head;	/*	 * Read the interrupt status, and write it back to clear the	 * interrupt cause	 */	status = inw(io_addr + USBSTS);	if (!status)	/* shared interrupt, not mine */		return;	outw(status, io_addr + USBSTS);		/* Clear it */	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {		if (status & USBSTS_HSE)			err("%x: host system error, PCI problems?", io_addr);		if (status & USBSTS_HCPE)			err("%x: host controller process error. something bad happened", io_addr);		if ((status & USBSTS_HCH) && !uhci->is_suspended) {			err("%x: host controller halted. very bad", io_addr);			/* FIXME: Reset the controller, fix the offending TD */		}	}	if (status & USBSTS_RD)		wakeup_hc(uhci);	uhci_free_pending_qhs(uhci);	uhci_remove_pending_qhs(uhci);	uhci_clear_next_interrupt(uhci);	/* Walk the list of pending URB's to see which ones completed */	spin_lock(&uhci->urb_list_lock);	head = &uhci->urb_list;	tmp = head->next;	while (tmp != head) {		struct urb *urb = list_entry(tmp, struct urb, urb_list);		tmp = tmp->next;		/* Checks the status and does all of the magic necessary */		uhci_transfer_result(uhci, urb);	}	spin_unlock(&uhci->urb_list_lock);	uhci_finish_completion(uhci);}static void reset_hc(struct uhci *uhci){	unsigned int io_addr = uhci->io_addr;	/* Global reset for 50ms */	outw(USBCMD_GRESET, io_addr + USBCMD);	wait_ms(50);	outw(0, io_addr + USBCMD);	wait_ms(10);}static void suspend_hc(struct uhci *uhci){	unsigned int io_addr = uhci->io_addr;	dbg("%x: suspend_hc", io_addr);	outw(USBCMD_EGSM, io_addr + USBCMD);	uhci->is_suspended = 1;}static void wakeup_hc(struct uhci *uhci){	unsigned int io_addr = uhci->io_addr;	unsigned int status;	dbg("%x: wakeup_hc", io_addr);	outw(0, io_addr + USBCMD);		/* wait for EOP to be sent */	status = inw(io_addr + USBCMD);	while (status & USBCMD_FGR)		status = inw(io_addr + USBCMD);	uhci->is_suspended = 0;	/* Run and mark it configured with a 64-byte max packet */	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);}static int ports_active(struct uhci *uhci){	unsigned int io_addr = uhci->io_addr;	int connection = 0;	int i;	for (i = 0; i < uhci->rh.numports; i++)		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1);	return connection;}static void start_hc(struct uhci *uhci){	unsigned int io_addr = uhci->io_addr;	int timeout = 1000;	/*	 * Reset the HC - this will force us to get a	 * new notification of any already connected	 * ports due to the virtual disconnect that it	 * implies.	 */	outw(USBCMD_HCRESET, io_addr + USBCMD);	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {		if (!--timeout) {			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");			break;		}	}	/* Turn on all interrupts */	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,		io_addr + USBINTR);	/* Start at frame 0 */	outw(0, io_addr + USBFRNUM);	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);	/* Run and mark it configured with a 64-byte max packet */	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);}#ifdef CONFIG_PROC_FSstatic int uhci_num = 0;#endifstatic void free_uhci(struct uhci *uhci){	kfree(uhci);}/* * De-allocate all resources.. */static void release_uhci(struct uhci *uhci){	int i;#ifdef CONFIG_PROC_FS	char buf[8];#endif	if (uhci->irq >= 0) {		free_irq(uhci->irq, uhci);		uhci->irq = -1;	}	for (i = 0; i < UHCI_NUM_SKELQH; i++)		if (uhci->skelqh[i]) {			uhci_free_qh(uhci, uhci->skelqh[i]);			uhci->skelqh[i] = NULL;		}	for (i = 0; i < UHCI_NUM_SKELTD; i++)		if (uhci->skeltd[i]) {			uhci_free_td(uhci, uhci->skeltd[i]);			uhci->skeltd[i] = NULL;		}	if (uhci->qh_pool) {		pci_pool_destroy(uhci->qh_pool);		uhci->qh_pool = NULL;	}	if (uhci->td_pool) {		pci_pool_destroy(uhci->td_pool);		uhci->td_pool = NULL;	}	if (uhci->fl) {		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);		uhci->fl = NULL;	}	if (uhci->bus) {		usb_free_bus(uhci->bus);		uhci->bus = NULL;	}#ifdef CONFIG_PROC_FS	if (uhci->proc_entry) {		sprintf(buf, "hc%d", uhci->num);		remove_proc_entry(buf, uhci_proc_root);		uhci->proc_entry = NULL;	}#endif	free_uhci(uhci);}/* * Allocate a frame list, and then setup the skeleton * * The hardware doesn't really know any difference * in the queues, but the order does matter for the * protocols higher up. The order is: * *  - any isochronous events handled before any *    of the queues. We don't do that here, because *    we'll create the actual TD entries on demand. *  - The first queue is the interrupt queue. *  - The second queue is the control queue, split into low and high speed *  - The third queue is bulk queue. *  - The fourth queue is the bandwidth reclamation queue, which loops back *    to the high speed control queue. */static int alloc_uhci(str

⌨️ 快捷键说明

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