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

📄 usb-ohci.c

📁 Usb Host/Periphel Control TD1120 codes
💻 C
📖 第 1 页 / 共 5 页
字号:
	}
	
	urb_priv->td_cnt = 0;

	if (data_len) 
	{
		data = pci_map_single (ohci->ohci_dev,
			urb->transfer_buffer, data_len,
			usb_pipeout (urb->pipe)
				? PCI_DMA_TODEVICE
				: PCI_DMA_FROMDEVICE
			);
	} 
	else
		data = 0;
	
	switch (usb_pipetype (urb->pipe)) 
	{
		case PIPE_BULK:

			/*
			if (usb_pipeout (urb->pipe))
			{
				printk(KERN_CRIT " ===> BULK OUT URB 0x%x\n", urb);
				submit_urb_out_debug();
			}
			else
				printk(KERN_CRIT " ===> BULK IN URB 0x%x\n", urb);
				*/


			info = usb_pipeout (urb->pipe)? 
				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
			while(data_len > 4096) 
			{		
				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
				data += 4096; data_len -= 4096; cnt++;
			}
			info = usb_pipeout (urb->pipe)?
				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
			cnt++;

			/* If the transfer size is multiple of the pipe mtu,
			 * we may need an extra TD to create a empty frame
			 * Note : another way to check this condition is
			 * to test if(urb_priv->length > cnt) - Jean II */
			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
			    usb_pipeout (urb->pipe) &&
			    (urb->transfer_buffer_length != 0) && 
			    ((urb->transfer_buffer_length % maxps) == 0)) 
			{
				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
				cnt++;
			}

			if (!ohci->sleeping) 
			{
				wmb();
				Ohci_WriteReg (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
			}
			break;

		case PIPE_INTERRUPT:
			info = usb_pipeout (urb->pipe)? 
				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
			td_fill (ohci, info, data, data_len, urb, cnt++);
			break;

		case PIPE_CONTROL:
			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
			td_fill (ohci, info,
				pci_map_single (ohci->ohci_dev,
					urb->setup_packet, 8,
					PCI_DMA_TODEVICE),
				8, urb, cnt++); 
			if (data_len > 0) {  
				info = usb_pipeout (urb->pipe)? 
					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
				/* NOTE:  mishandles transfers >8K, some >4K */
				td_fill (ohci, info, data, data_len, urb, cnt++);  
			} 
			info = usb_pipeout (urb->pipe)? 
 				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
			td_fill (ohci, info, data, 0, urb, cnt++);
			if (!ohci->sleeping) {
				wmb();
				Ohci_WriteReg (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
			}
			break;

		case PIPE_ISOCHRONOUS:
			
	//		printk(KERN_CRIT "+ td_submit_urb: %x \n", urb);

			for (cnt = 0; cnt < urb->number_of_packets; cnt++) 
			{
				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
					data + urb->iso_frame_desc[cnt].offset, 
					urb->iso_frame_desc[cnt].length, urb, cnt); 
			}
			break;
	} 
	if (urb_priv->length != cnt) 
		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
}

/*-------------------------------------------------------------------------*
 * Done List handling functions
 *-------------------------------------------------------------------------*/


/* calculate the transfer length and update the urb */

static void dl_transfer_length(td_t * td)
{
	__u32 tdINFO, tdBE, tdCBP;
 	__u16 tdPSW;
 	urb_t * urb = td->urb;
 	urb_priv_t * urb_priv = urb->hcpriv;
	int dlen = 0;
	int cc = 0;
	
	tdINFO = le32_to_cpup (&td->hwINFO);
  	tdBE   = le32_to_cpup (&td->hwBE);
  	tdCBP  = le32_to_cpup (&td->hwCBP);


  	if (tdINFO & TD_ISO) {
 		tdPSW = le16_to_cpu (td->hwPSW[0]);
 		cc = (tdPSW >> 12) & 0xF;
		if (cc < 0xE)  {
			if (usb_pipeout(urb->pipe)) {
				dlen = urb->iso_frame_desc[td->index].length;
			} else {
				dlen = tdPSW & 0x3ff;
			}
			urb->actual_length += dlen;
			urb->iso_frame_desc[td->index].actual_length = dlen;
			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
				cc = TD_CC_NOERROR;
					 
			urb->iso_frame_desc[td->index].status = cc_to_error[cc];
		}
	} else { /* BULK, INT, CONTROL DATA */
		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 
				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
 			if (tdBE != 0) {
 				if (td->hwCBP == 0)
					urb->actual_length += tdBE - td->data_dma + 1;
  				else
					urb->actual_length += tdCBP - td->data_dma;
			}
  		}
  	}
}

/* handle an urb that is being unlinked */

static void dl_del_urb (urb_t * urb)
{
	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;

	urb_rm_priv_locked (urb);

	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
		urb->status = -ECONNRESET;
		if (urb->complete)
			urb->complete (urb);
	} else {
		urb->status = -ENOENT;

		/* unblock sohci_unlink_urb */
		if (wait_head)
			wake_up (wait_head);
	}
}

/*-------------------------------------------------------------------------*/

/* replies to the request have to be on a FIFO basis so
 * we reverse the reversed done-list */
 
static td_t * dl_reverse_done_list (ohci_t * ohci)
{
	__u32 td_list_hc;
	td_t * td_rev = NULL;
	td_t * td_list = NULL;
  	urb_priv_t * urb_priv = NULL;
  	unsigned long flags;
  	
  	spin_lock_irqsave (&usb_ed_lock, flags);
  	
	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
	ohci->hcca->done_head = 0;
	
	while (td_list_hc) {		
		td_list = dma_to_td (ohci, td_list_hc);

		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
			dbg(" USB-error/status: %x : %p", 
					TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
					td_list->ed->hwHeadP = 
						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
				} else 
					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
			}
		}

		td_list->next_dl_td = td_rev;	
		td_rev = td_list;
		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
	}	
	spin_unlock_irqrestore (&usb_ed_lock, flags);
	return td_list;
}

/*-------------------------------------------------------------------------*/

/* there are some pending requests to remove 
 * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
 * - some URBs/TDs if urb_priv->state == URB_DEL */
 
static void dl_del_list (ohci_t  * ohci, unsigned int frame)
{
	unsigned long flags;
	ed_t * ed;
	__u32 edINFO;
	__u32 tdINFO;
	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
	__u32 * td_p;
	int ctrl = 0, bulk = 0;

	spin_lock_irqsave (&usb_ed_lock, flags);

	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {

		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
		edINFO = le32_to_cpup (&ed->hwINFO);
		td_p = &ed->hwHeadP;

		for (td = tdHeadP; td != tdTailP; td = td_next) { 
			urb_t * urb = td->urb;
			urb_priv_t * urb_priv = td->urb->hcpriv;
			
			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
				tdINFO = le32_to_cpup (&td->hwINFO);
				if (TD_CC_GET (tdINFO) < 0xE)
					dl_transfer_length (td);
				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));

				/* URB is done; clean up */
				if (++(urb_priv->td_cnt) == urb_priv->length)
					dl_del_urb (urb);
			} else {
				td_p = &td->hwNextTD;
			}
		}

		if (ed->state & ED_DEL) { /* set by sohci_free_dev */
			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
			td_free (ohci, tdTailP); /* free dummy td */
   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
			ed->state = ED_NEW;
			hash_free_ed(ohci, ed);
   	 		/* if all eds are removed wake up sohci_free_dev */
   	 		if (!--dev->ed_cnt) {
				wait_queue_head_t *wait_head = dev->wait;

				dev->wait = 0;
				if (wait_head)
					wake_up (wait_head);
			}
   	 	} else {
   	 		ed->state &= ~ED_URB_DEL;
			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);

			if (tdHeadP == tdTailP) {
				if (ed->state == ED_OPER)
					ep_unlink(ohci, ed);
				td_free (ohci, tdTailP);
				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
				ed->state = ED_NEW;
				hash_free_ed(ohci, ed);
				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
			} else
   	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
   	 	}

		switch (ed->type) {
			case PIPE_CONTROL:
				ctrl = 1;
				break;
			case PIPE_BULK:
				bulk = 1;
				break;
		}
   	}
   	
	/* maybe reenable control and bulk lists */ 
	if (!ohci->disabled) {
		if (ctrl) 	/* reset control list */
			Ohci_WriteReg (0, &ohci->regs->ed_controlcurrent);
		if (bulk)	/* reset bulk list */
			Ohci_WriteReg (0, &ohci->regs->ed_bulkcurrent);
		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
			if (ohci->ed_controltail)
				ohci->hc_control |= OHCI_CTRL_CLE;
			if (ohci->ed_bulktail)
				ohci->hc_control |= OHCI_CTRL_BLE;
			Ohci_WriteReg (ohci->hc_control, &ohci->regs->control);   
		}
	}

   	ohci->ed_rm_list[frame] = NULL;
   	spin_unlock_irqrestore (&usb_ed_lock, flags);
}


  		
/*-------------------------------------------------------------------------*/

void urb_return_debug()
{
}
/* td done list */

static void dl_done_list (ohci_t * ohci, td_t * td_list)
{
  	td_t * td_list_next = NULL;
	ed_t * ed;
	int cc = 0;
	urb_t * urb;
	urb_priv_t * urb_priv;
 	__u32 tdINFO, edHeadP, edTailP;
 	
 	unsigned long flags;
	

	//ying
	int i;
	unsigned int pipe;
 	
  	while (td_list) 
	{
   		
		td_list_next = td_list->next_dl_td;
   		
  		urb = td_list->urb;
  		urb_priv = urb->hcpriv;
  		tdINFO = le32_to_cpup (&td_list->hwINFO);
  		
   		ed = td_list->ed;

   		dl_transfer_length(td_list);
 			
  		/* error code of transfer */
  		cc = TD_CC_GET (tdINFO);
  		if (cc == TD_CC_STALL)
			usb_endpoint_halt(urb->dev,
				usb_pipeendpoint(urb->pipe),
				usb_pipeout(urb->pipe));
  		
  		if (!(urb->transfer_flags & USB_DISABLE_SPD)
				&& (cc == TD_DATAUNDERRUN))
			cc = TD_CC_NOERROR;

  		if (++(urb_priv->td_cnt) == urb_priv->length) 
		{
			if ((ed->state & (ED_OPER | ED_UNLINK))
					&& (urb_priv->state != URB_DEL)) 
			{
  				urb->status = cc_to_error[cc];

/*
				printk(KERN_CRIT " <=== URB 0x%x, status %d, trans_len %d, actual_len %d, ed:desc 0x%x \n", 
											urb, 
											urb->status, 
											urb->transfer_buffer_length,
											urb->actual_length,
											ed->hwINFO);

				//ying
				pipe = urb->pipe;

				if (( usb_pipetype (pipe) == PIPE_CONTROL) && (urb->actual_length == 0x12))
				{
					urb_return_debug();
				
					for ( i=0; i< urb->actual_length; i++)
					{
						printk(KERN_CRIT "Offset[%d]:%x \n", i, *((unsigned char*)urb->transfer_buffer + i));
					}
					printk(KERN_CRIT "\n");
					

				}
				//end of testing
*/
				sohci_return_urb (ohci, urb);
  			} 
			else 
			{
				spin_lock_irqsave (&usb_ed_lock, flags);
  				dl_del_urb (urb);
				spin_unlock_irqrestore (&usb_ed_lock, flags);
			}
  		}
  		
  		spin_lock_irqsave (&usb_ed_lock, flags);
  		
		if (ed->state != ED_NEW) 
		{ 
  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
  			edTailP = le32_to_cpup (&ed->hwTailP);

			/* unlink eds if they are not busy */
     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
     				ep_unlink (ohci, ed);
     		
		}	
     	spin_unlock_irqrestore (&usb_ed_lock, flags);
     	
    	td_list = td_list_next;
  	}  
}




/*-------------------------------------------------------------------------*
 * Virtual Root Hub 
 *-------------------------------------------------------------------------*/
 
/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
	0x12,       /*  __u8  bLength; */
	0x01,       /*  __u8  bDescriptorType; Device */
	0x10,	    /*  __u16 bcdUSB; v1.1 */
	0x01,
	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
	0x00,	    /*  __u8  bDeviceSubClass; */
	0x00,       /*  __u8  bDeviceProtocol; */
	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
	0x00,       /*  __u16 idVendor; */
	0x00,
	0x00,       /*  __u16 idProduct; */
 	0x00,
	0x00,       /*  __u16 bcdDevice; */
 	0x00,
	0x00,       /*  __u8  iManufacturer; */
	0x02,       /*  __u8  iProduct; */
	0x01,       /*  __u8  iSerialNumber; */
	0x01        /*  __u8  bNumConfigurations; */
};

⌨️ 快捷键说明

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