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

📄 hc_crisv10.c

📁 usb driver for 2.6.17
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (urb->bandwidth == 0) {			bustime = usb_check_bandwidth(urb->dev, urb);			if (bustime < 0) {				ret = bustime;			} else {				ret = etrax_usb_submit_isoc_urb(urb);				if (ret == 0)					usb_claim_bandwidth(urb->dev, urb, bustime, 0);			}		} else {			/* Bandwidth already set. */			ret = etrax_usb_submit_isoc_urb(urb);		}	}	DBFEXIT;        if (ret != 0)          printk("Submit URB error %d\n", ret);	return ret;}static int etrax_usb_unlink_urb(struct urb *urb, int status){	etrax_hc_t *hc;	etrax_urb_priv_t *urb_priv;	int epid;	unsigned int flags;	DBFENTER;	if (!urb) {		return -EINVAL;	}	/* Disable interrupts here since a descriptor interrupt for the isoc epid	   will modify the sb list.  This could possibly be done more granular, but	   unlink_urb should not be used frequently anyway.	*/	save_flags(flags);	cli();	if (!urb->dev || !urb->dev->bus) {		restore_flags(flags);		return -ENODEV;	}	if (!urb->hcpriv) {		/* This happens if a device driver calls unlink on an urb that		   was never submitted (lazy driver) or if the urb was completed		   while unlink was being called. */		restore_flags(flags);		return 0;	}	if (urb->transfer_flags & URB_ASYNC_UNLINK) {		/* FIXME. */		/* If URB_ASYNC_UNLINK is set:		   unlink		   move to a separate urb list		   call complete at next sof with ECONNRESET		   If not:		   wait 1 ms		   unlink		   call complete with ENOENT		*/		warn("URB_ASYNC_UNLINK set, ignoring.");	}	/* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,	   but that doesn't work for interrupt and isochronous traffic since they are completed	   repeatedly, and urb->status is set then. That may in itself be a bug though. */	hc = urb->dev->bus->hcpriv;	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;	epid = urb_priv->epid;	/* Set the urb status (synchronous unlink). */	urb->status = -ENOENT;	urb_priv->urb_state = UNLINK;	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {		int ret;		ret = etrax_rh_unlink_urb(urb);		DBFEXIT;		restore_flags(flags);		return ret;	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {		dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);		if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {			/* The EP was enabled, disable it and wait. */			TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);			/* Ah, the luxury of busy-wait. */			while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));		}		/* Kicking dummy list out of the party. */		TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);		if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {			/* The EP was enabled, disable it and wait. */			TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);			/* Ah, the luxury of busy-wait. */			while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));		}	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {		dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);		/* Separate function because it's a tad more complicated. */		etrax_usb_unlink_intr_urb(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {		dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);		if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {			/* The EP was enabled, disable it and wait. */			TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);			/* Ah, the luxury of busy-wait. */			while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));		}	}	/* Note that we need to remove the urb from the urb list *before* removing its SB	   descriptors. (This means that the isoc eof handler might get a null urb when we	   are unlinking the last urb.) */	if (usb_pipetype(urb->pipe) == PIPE_BULK) {		urb_list_del(urb, epid);		TxBulkEPList[epid].sub = 0;		etrax_remove_from_sb_list(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		urb_list_del(urb, epid);		TxCtrlEPList[epid].sub = 0;		etrax_remove_from_sb_list(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {		urb_list_del(urb, epid);		/* Sanity check (should never happen). */		assert(urb_list_empty(epid));		/* Release allocated bandwidth. */		usb_release_bandwidth(urb->dev, urb, 0);	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {		if (usb_pipeout(urb->pipe)) {			USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;			if (__urb_list_entry(urb, epid)) {				urb_list_del(urb, epid);				iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;				prev_sb = 0;				while (iter_sb && (iter_sb != urb_priv->first_sb)) {					prev_sb = iter_sb;					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;				}				if (iter_sb == 0) {					/* Unlink of the URB currently being transmitted. */					prev_sb = 0;					iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;				}				while (iter_sb && (iter_sb != urb_priv->last_sb)) {					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;				}				if (iter_sb) {					next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;				} else {					/* This should only happen if the DMA has completed					   processing the SB list for this EP while interrupts					   are disabled. */					dbg_isoc("Isoc urb not found, already sent?");					next_sb = 0;				}				if (prev_sb) {					prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;				} else {					TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;				}				etrax_remove_from_sb_list(urb);				if (urb_list_empty(epid)) {					TxIsocEPList[epid].sub = 0;					dbg_isoc("Last isoc out urb epid %d", epid);				} else if (next_sb || prev_sb) {					dbg_isoc("Re-enable isoc out epid %d", epid);					TxIsocEPList[epid].hw_len = 0;					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);				} else {					TxIsocEPList[epid].sub = 0;					dbg_isoc("URB list non-empty and no SB list, EP disabled");				}			} else {				dbg_isoc("Urb 0x%p not found, completed already?", urb);			}		} else {			urb_list_del(urb, epid);			/* For in traffic there is only one SB descriptor for each EP even			   though there may be several urbs (all urbs point at the same SB). */			if (urb_list_empty(epid)) {				/* No more urbs, remove the SB. */				TxIsocEPList[epid].sub = 0;				etrax_remove_from_sb_list(urb);			} else {				TxIsocEPList[epid].hw_len = 0;				TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);			}		}		/* Release allocated bandwidth. */		usb_release_bandwidth(urb->dev, urb, 1);	}	/* Free the epid if urb list is empty. */	if (urb_list_empty(epid)) {		etrax_usb_free_epid(epid);	}	restore_flags(flags);	/* Must be done before calling completion handler. */	kfree(urb_priv);	urb->hcpriv = 0;	if (urb->complete) {		urb->complete(urb, NULL);	}	DBFEXIT;	return 0;}static int etrax_usb_get_frame_number(struct usb_device *usb_dev){	DBFENTER;	DBFEXIT;	return (*R_USB_FM_NUMBER & 0x7ff);}static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs){	DBFENTER;	/* This interrupt handler could be used when unlinking EP descriptors. */	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {		USB_EP_Desc_t *ep;		//dbg_bulk("dma8_sub0_descr (BULK) intr.");		/* It should be safe clearing the interrupt here, since we don't expect to get a new		   one until we restart the bulk channel. */		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);		/* Wait while the DMA is running (though we don't expect it to be). */		while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));		/* Advance the DMA to the next EP descriptor. */		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);		//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);		/* ep->next is already a physical address; no need for a virt_to_phys. */		*R_DMA_CH8_SUB0_EP = ep->next;		/* Start the DMA bulk channel again. */		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);	}	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {		struct urb *urb;		int epid;		etrax_urb_priv_t *urb_priv;		unsigned long int flags;		dbg_ctrl("dma8_sub1_descr (CTRL) intr.");		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);		/* The complete callback gets called so we cli. */		save_flags(flags);		cli();		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {			if ((TxCtrlEPList[epid].sub == 0) ||			    (epid == DUMMY_EPID) ||			    (epid == INVALID_EPID)) {				/* Nothing here to see. */				continue;			}			/* Get the first urb (if any). */			urb = urb_list_first(epid);			if (urb) {				/* Sanity check. */				assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;				assert(urb_priv);				if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {					assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));					etrax_usb_complete_urb(urb, 0);				}			}		}		restore_flags(flags);	}	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {		dbg_intr("dma8_sub2_descr (INTR) intr.");		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);	}	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {		struct urb *urb;		int epid;		int epid_done;		etrax_urb_priv_t *urb_priv;		USB_SB_Desc_t *sb_desc;		usb_isoc_complete_data_t *comp_data = NULL;		/* One or more isoc out transfers are done. */		dbg_isoc("dma8_sub3_descr (ISOC) intr.");		/* For each isoc out EP search for the first sb_desc with the intr flag		   set.  This descriptor must be the last packet from an URB.  Then		   traverse the URB list for the EP until the URB with urb_priv->last_sb		   matching the intr-marked sb_desc is found.  All URBs before this have		   been sent.		*/		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {			/* Skip past epids with no SB lists, epids used for in traffic,			   and special (dummy, invalid) epids. */			if ((TxIsocEPList[epid].sub == 0) ||			    (test_bit(epid, (void *)&epid_out_traffic) == 0) ||			    (epid == DUMMY_EPID) ||			    (epid == INVALID_EPID)) {				/* Nothing here to see. */				continue;			}			sb_desc = phys_to_virt(TxIsocEPList[epid].sub);			/* Find the last descriptor of the currently active URB for this ep.			   This is the first descriptor in the sub list marked for a descriptor			   interrupt. */			while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {				sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;			}			assert(sb_desc);			dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",				 epid,				 phys_to_virt(TxIsocEPList[epid].sub),				 sb_desc);			epid_done = 0;			/* Get the first urb (if any). */			urb = urb_list_first(epid);			assert(urb);			while (urb && !epid_done) {				/* Sanity check. */				assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);				if (!usb_pipeout(urb->pipe)) {					/* descr interrupts are generated only for out pipes. */					epid_done = 1;					continue;				}				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;				assert(urb_priv);				if (sb_desc != urb_priv->last_sb) {					/* This urb has been sent. */					dbg_isoc("out URB 0x%p sent", urb);					urb_priv->urb_state = TRANSFER_DONE;				} else if ((sb_desc == urb_priv->last_sb) &&					   !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {					assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));					assert(sb_desc->next == 0);					dbg_isoc("out URB 0x%p last in list, epid disabled", urb);					TxIsocEPList[epid].sub = 0;					TxIsocEPList[epid].hw_len = 0;					urb_priv->urb_state = TRANSFER_DONE;					epid_done = 1;				} else {					epid_done = 1;				}				if (!epid_done) {					urb = urb_list_next(urb, epid);				}			}		}		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);		comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);		assert(comp_data != NULL);                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);                schedule_work(&comp_data->usb_bh);	}	DBFEXIT;        return IRQ_HANDLED;

⌨️ 快捷键说明

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