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

📄 usb-host.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
                urb = urb_list_first(epid);                //printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);                                if (!urb) {                        err("No urb for epid %d in rx interrupt", epid);			__dump_ept_data(epid);                        goto skip_out;                }                /* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since                   ctrl pipes are not. */                		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {			__u32 r_usb_ept_data;			warn("error in rx desc->status, epid %d, first urb = 0x%lx",                              epid, (unsigned long)urb);			__dump_in_desc(myNextRxDesc);                        *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);                         nop();                        r_usb_ept_data = *R_USB_EPT_DATA;			warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);			warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);                        etrax_usb_complete_urb(urb, -EPROTO);			goto skip_out;		}                urb_priv = (etrax_urb_priv_t *)urb->hcpriv;                assert(urb_priv);                                if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||                     (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||                    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {                        if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {                                /* We get nodata for empty data transactions, and the rx descriptor's                                   hw_len field is not valid in that case. No data to copy in other                                    words. */                        } else {                                /* Make sure the data fits in the buffer. */                                assert(urb_priv->rx_offset + myNextRxDesc->hw_len                                        <= urb->transfer_buffer_length);                                memcpy(urb->transfer_buffer + urb_priv->rx_offset,                                       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);	                                urb_priv->rx_offset += myNextRxDesc->hw_len;                        }                        if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {                                etrax_usb_complete_urb(urb, 0);                        }                } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {                                                iso_packet_descriptor_t *packet;                        if (urb_priv->urb_state == UNLINK) {                                info("Ignoring rx data for urb being unlinked.");                                goto skip_out;                        } else if (urb_priv->urb_state == NOT_STARTED) {                                info("What? Got rx data for urb that isn't started?");                                goto skip_out;                        }                                                        packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];                        packet->status = 0;                         if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {                                /* We get nodata for empty data transactions, and the rx descriptor's                                   hw_len field is not valid in that case. We copy 0 bytes however to                                   stay in synch. */                                packet->actual_length = 0;                                                        } else {                                packet->actual_length = myNextRxDesc->hw_len;                                /* Make sure the data fits in the buffer. */                                assert(packet->actual_length <= packet->length);                                                                memcpy(urb->transfer_buffer + packet->offset,                                       phys_to_virt(myNextRxDesc->buf), packet->actual_length);                        }                        /* Increment the packet counter. */                        urb_priv->isoc_packet_counter++;	                                                /* Note that we don't care about the eot field in the rx descriptor's status.                           It will always be set for isoc traffic. */			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {                                /* Out-of-synch diagnostics. */                                curr_fm = (*R_USB_FM_NUMBER & 0x7ff);                                if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {                                        warn("Out of synch? Previous frame = %d, current frame = %d",                                             prev_fm, curr_fm);                                }                                prev_fm = curr_fm;				/* Complete the urb with status OK. */				etrax_usb_complete_isoc_urb(urb, 0);				/* Must set this to 0 since this urb is still active after				   completion. */				urb_priv->isoc_packet_counter = 0;			}                }                	skip_out:                /* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr		   has the same layout as USB_IN_Desc for the relevant fields.) */                prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);		myPrevRxDesc = myNextRxDesc;		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);		myLastRxDesc = myPrevRxDesc;		myNextRxDesc->status = 0;		myNextRxDesc = phys_to_virt(myNextRxDesc->next);	}        restore_flags(flags);                DBFEXIT;        }/* This function will unlink the SB descriptors associated with this urb. */static int etrax_remove_from_sb_list(urb_t *urb){	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;	etrax_urb_priv_t *urb_priv;	int i = 0;	DBFENTER;	urb_priv = (etrax_urb_priv_t *)urb->hcpriv; 	assert(urb_priv);        /* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor	   doesn't really need to be disabled, it's just that we expect it to be. */        if (usb_pipetype(urb->pipe) == PIPE_BULK) {                assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));        } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {                assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));        } 	first_sb = urb_priv->first_sb;	last_sb = urb_priv->last_sb;	        assert(first_sb);        assert(last_sb);        	while (first_sb != last_sb) {		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);		kmem_cache_free(usb_desc_cache, first_sb);		first_sb = next_sb;		i++;	}	kmem_cache_free(usb_desc_cache, last_sb);	i++;	dbg_sb("%d SB descriptors freed", i);	/* Compare i with urb->number_of_packets for Isoc traffic. 	   Should be same when calling unlink_urb */		DBFEXIT;		return i;}static int etrax_usb_submit_bulk_urb(urb_t *urb){	int epid;        int empty;        unsigned long flags;        	DBFENTER;        /* Epid allocation, empty check and list add must be protected.            Read about this in etrax_usb_submit_ctrl_urb. */        spin_lock_irqsave(&urb_list_lock, flags);	epid = etrax_usb_setup_epid(urb);	if (epid == -1) {		DBFEXIT;                spin_unlock_irqrestore(&urb_list_lock, flags);		return -ENOMEM;	}        empty = urb_list_empty(epid);        urb_list_add(urb, epid);        spin_unlock_irqrestore(&urb_list_lock, flags);        /* USB_QUEUE_BULK is UHCI-specific, but we warn anyway. */        if (!(urb->transfer_flags & USB_QUEUE_BULK) && !empty) {                warn("USB_QUEUE_BULK is not set and urb queue is not empty, ignoring.");        }        dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",                  usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);        /* Mark the urb as being in progress. */	urb->status = -EINPROGRESS;        if (empty) {                etrax_usb_add_to_bulk_sb_list(urb, epid);        }	        	DBFEXIT;	return 0;}static void etrax_usb_add_to_bulk_sb_list(urb_t *urb, int epid){	USB_SB_Desc_t *sb_desc;	etrax_urb_priv_t *urb_priv;	unsigned long flags;	char maxlen;	DBFENTER;	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));		urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);	assert(urb_priv != NULL);        /* This sets rx_offset to 0. */        memset(urb_priv, 0, sizeof(etrax_urb_priv_t));        	sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);	assert(sb_desc != NULL);	memset(sb_desc, 0, sizeof(USB_SB_Desc_t));	if (usb_pipeout(urb->pipe)) {                		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);                                /* This is probably a sanity check of the bulk transaction length                   not being larger than 64 kB. */		if (urb->transfer_buffer_length > 0xffff) {			panic("urb->transfer_buffer_length > 0xffff");		}		sb_desc->sw_len = urb->transfer_buffer_length;                /* The rem field is don't care if it's not a full-length transfer, so setting                   it shouldn't hurt. Also, rem isn't used for OUT traffic. */		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |                                    IO_STATE(USB_SB_command, tt, out) |                                    IO_STATE(USB_SB_command, eot, yes) |                                    IO_STATE(USB_SB_command, eol, yes));                /* The full field is set to yes, even if we don't actually check that this is                   a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).                   Setting full prevents the USB controller from sending an empty packet in                   that case.  However, if USB_ZERO_PACKET was set we want that. */                if (!(urb->transfer_flags & USB_ZERO_PACKET)) {                        sb_desc->command |= IO_STATE(USB_SB_command, full, yes);                }		sb_desc->buf = virt_to_phys(urb->transfer_buffer);		sb_desc->next = 0;			} else if (usb_pipein(urb->pipe)) {                dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);		sb_desc->sw_len = urb->transfer_buffer_length ?			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;		                /* The rem field is don't care if it's not a full-length transfer, so setting                   it shouldn't hurt. */		sb_desc->command =			(IO_FIELD(USB_SB_command, rem,                                  urb->transfer_buffer_length % maxlen) |                         IO_STATE(USB_SB_command, tt, in) |                         IO_STATE(USB_SB_command, eot, yes) |                         IO_STATE(USB_SB_command, eol, yes));				sb_desc->buf = 0;		sb_desc->next = 0;	}		urb_priv->first_sb = sb_desc;	urb_priv->last_sb = sb_desc;	urb_priv->epid = epid;	urb->hcpriv = urb_priv;		/* Reset toggle bits and reset error count. */	save_flags(flags);	cli();	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);         nop();        /* FIXME: Is this a special case since the hold field is checked,           or should we check hold in a lot of other cases as well? */	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {		panic("Hold was set in %s", __FUNCTION__);	}        /* Reset error counters (regardless of which direction this traffic is). */	*R_USB_EPT_DATA &=		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |		  IO_MASK(R_USB_EPT_DATA, error_count_out));	        /* Software must preset the toggle bits. */	if (usb_pipeout(urb->pipe)) {		char toggle =                        usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);	} else {		char toggle =                        usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);	}                        /* Assert that the EP descriptor is disabled. */        assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));        /* The reason we set the EP's sub pointer directly instead of           walking the SB list and linking it last in the list is that we only           have one active urb at a time (the rest are queued). */	/* Note that we cannot have interrupts running when we have set the SB descriptor	   but the EP is not yet enabled.  If a bulk eot happens for another EP, we will	   find this EP disabled and with a SB != 0, which will make us think that it's done. */	TxBulkEPList[epid].sub = virt_to_phys(sb_desc);	TxBulkEPList[epid].hw_len = 0;        /* Note that we don't have to fill in the ep_id field since this           was done when we allocated the EP descriptors in init_tx_bulk_ep. */	/* Check if the dummy list is already with us (if several urbs were queued). */	if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {		dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d", 			 (unsigned long)urb, epid);		/* The last EP in the dummy list already has its next pointer set to 		   TxBulkEPList[epid].next. */		/* We don't need to check if the DMA is at this EP or not before changing the		   next pointer, since we will do it in one 32-bit write (EP descriptors are		   32-bit aligned). */		TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);	}        /* Enable the EP descr. */	dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);        TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);	/* Everything is set up, safe to enable interrupts again. */	restore_flags(flags);        /* If the DMA bulk channel isn't running, we need to restart it if it	   has stopped at the last EP descriptor (DMA stopped because there was	   no more traffic) or if it has stopped at a dummy EP with the intr flag	   set (DMA stopped because we were too slow in inserting new traffic). */	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {		USB_EP_Desc_t *ep;		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);		dbg_bulk("DMA channel not running in add");		dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);		if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||		    (ep->command & 0x8) >> 3) {			*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);			/* Update/restart the bulk start timer since we just started the channel. */			mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);			/* Update/restart the bulk eot timer since we just inserted traffic. */			mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);		}	}

⌨️ 快捷键说明

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