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

📄 usb-ohci.c

📁 有关于USB的一些主机端驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
/*				pci_map_single (ohci->ohci_dev,		//modified by Changming HUANG
					urb->setup_packet, 8,
					PCI_DMA_TODEVICE),*/
				mpuva_to_lbva(urb->setup_packet),	//added by Changming HUANG
				8, urb, cnt++); 

//			printf("setup_packet Virt address:%X\n",urb->setup_packet);
//			printf("setup_packet LB address :%X\n",mpuva_to_lbva(urb->setup_packet));
				
			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++);
//			printf("start control list\n");
			if (!ohci->sleeping){
//				hc_register_info(ohci);
//				printf("[Start Control]Command control:\t%X\n",readl(&ohci->regs->control));
				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */				
//				wait_ms(50);
//				hc_register_info(ohci);
//				printf("Start Control list\n");
			}
			break;

		case PIPE_ISOCHRONOUS:
			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) 
//		printf("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
}

/*-------------------------------------------------------------------------*
 * Interface functions (URB)
 *-------------------------------------------------------------------------*/

/* return a request to the completion handler */
 
static int sohci_return_urb (struct ohci *hc, urb_t * urb)
{
	urb_priv_t * urb_priv = urb->hcpriv;
	urb_t * urbt;
//	unsigned long flags;
	int i;
	
	if (!urb_priv)
		return -1; /* urb already unlinked */

	/* just to be sure */
	if (!urb->complete) {
//		urb_rm_priv (urb);
		return -1;
	}
	
#ifdef DEBUG
	urb_print (urb, "RET", usb_pipeout (urb->pipe));
#endif

	switch (usb_pipetype (urb->pipe)) {
  		case PIPE_INTERRUPT:
/*			pci_unmap_single (hc->ohci_dev,		//modified by Changming HUANG
				urb_priv->td [0]->data_dma,
				urb->transfer_buffer_length,
				usb_pipeout (urb->pipe)
					? PCI_DMA_TODEVICE
					: PCI_DMA_FROMDEVICE);*/
			urb->complete (urb);

			/* implicitly requeued */
  			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 */	
/*				pci_unmap_single (hc->ohci_dev,		//modified by Changming HUANG
					urb_priv->td [0]->data_dma,
					urb->transfer_buffer_length,
					usb_pipeout (urb->pipe)
						? PCI_DMA_TODEVICE
						: PCI_DMA_FROMDEVICE);*/
				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);
				urb->complete (urb); 	
				;
			}		
			break;
  				
		case PIPE_BULK:
		case PIPE_CONTROL: /* unlink URB, call complete */
//			urb_rm_priv (urb);
			urb->complete (urb);	
			break;
	}
	return 0;
}

/*-------------------------------------------------------------------------*/
ed_t * ep_add_ed (
	struct usb_device * usb_dev,
	unsigned int pipe,
	int interval,
	int load
)
{
   	ohci_t * ohci = usb_dev->bus->hcpriv;
	td_t * td;
	ed_t * ed_ret;
	volatile ed_t * ed; 
//	unsigned long flags;
 	
 	
//	spin_lock_irqsave (&usb_ed_lock, flags);

	ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);

	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
		/* pending delete request */
//		spin_unlock_irqrestore (&usb_ed_lock, flags);
		return NULL;
	}

//	printf("PIPE is:%X\n",pipe);
	
	if (ed->state == ED_NEW) {
//		printf("ED NEW status,so skip the ed to next ed\n");
//		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
		ed->hwINFO =OHCI_ED_SKIP; /* skip ed */
  		/* dummy td; end of td list for ed */
		td = td_alloc (ohci);

		printf("First TD MPUVA:0x%X   LBVA:0x%X\n",td,td->td_dma);
  		
		/* hash the ed for later reverse mapping */
// 		if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
 		if (!td ) {
			/* out of memory */
//		        if (td)
//		            td_free(ohci, td);
//			spin_unlock_irqrestore (&usb_ed_lock, flags);
			return NULL;
		}
//		ed->hwTailP = cpu_to_le32 (td->td_dma);
		ed->hwTailP = td->td_dma;
		ed->hwHeadP = ed->hwTailP;	
		ed->state = ED_UNLINK;
		ed->type = usb_pipetype (pipe);
		usb_to_ohci (usb_dev)->ed_cnt++;
	}

//	printf("TD address:%X\n",ed->hwTailP);
	ohci->dev[usb_pipedevice (pipe)] = usb_dev;
	
//	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
	ed->hwINFO = (usb_pipedevice (pipe)
			| usb_pipeendpoint (pipe) << 7
			| (usb_pipeisoc (pipe)? 0x8000: 0)
			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
			| usb_pipeslow (pipe) << 13
			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
  
  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
  		ed->int_period = interval;
  		ed->int_load = load;
  	}
  	
//	spin_unlock_irqrestore (&usb_ed_lock, flags);
	return ed_ret; 
}

/*-------------------------------------------------------------------------*/
 
/* request the removal of an endpoint
 * put the ep on the rm_list and request a stop of the bulk or ctrl list 
 * real removal is done at the next start frame (SF) hardware interrupt */
 
void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
{    
	unsigned int frame;
	ohci_t * ohci = usb_dev->bus->hcpriv;

	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
		return;
	
	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);

	if (!ohci->disabled) {
		switch (ed->type) {
			case PIPE_CONTROL: /* stop control list */
				ohci->hc_control &= ~OHCI_CTRL_CLE;
				writel (ohci->hc_control, &ohci->regs->control); 
  				break;
			case PIPE_BULK: /* stop bulk list */
				ohci->hc_control &= ~OHCI_CTRL_BLE;
				writel (ohci->hc_control, &ohci->regs->control); 
				break;
		}
	}

	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
	ed->ed_rm_list = ohci->ed_rm_list[frame];
	ohci->ed_rm_list[frame] = ed;

	if (!ohci->disabled && !ohci->sleeping) {
		/* enable SOF interrupt */
		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
		printf("SOF Enable -ep_rm_ed\n");
	}
}

/* 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 maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
	int i, size = 0;
//	unsigned long flags;
	int bustime = 0;
//	int mem_flags = ALLOC_FLAGS;
	
	if (!urb->dev || !urb->dev->bus)
		return -ENODEV;
	
	if (urb->hcpriv)			/* urb already in use */
		return -EINVAL;

//	if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) 
//		return -EPIPE;
	
	usb_inc_dev_use (urb->dev);
	ohci = (ohci_t *) urb->dev->bus->hcpriv;
	
#ifdef DEBUG
	urb_print (urb, "SUB", usb_pipein (pipe));
#endif

	/* handle a request to the virtual root hub */
	if (usb_pipedevice (pipe) == ohci->rh.devnum) 
		return rh_submit_urb (urb);

//	printf("Root hub DevNum:%d\n",ohci->rh.devnum);//added by Changming HUANG
//	printf("PIPE device is:%d\n",usb_pipedevice (pipe));

	/* when controller's hung, permit only roothub cleanup attempts
	 * such as powering down ports */
	if (ohci->disabled) {
		usb_dec_dev_use (urb->dev);	
		return -ESHUTDOWN;
	}

	/* every endpoint has a ed, locate and fill it */
	if (!(ed = (ed_t *)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;

			/* If the transfer size is multiple of the pipe mtu,
			 * we may need an extra TD to create a empty frame
			 * Jean II */
			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
			    usb_pipeout (pipe) &&
			    (urb->transfer_buffer_length != 0) && 
			    ((urb->transfer_buffer_length % maxps) == 0))
				size++;
			break;
		case PIPE_ISOCHRONOUS: /* number of packets from URB */
			size = urb->number_of_packets;
			if (size <= 0) {
				usb_dec_dev_use (urb->dev);	
				return -EINVAL;
			}
			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 of the URB */
	urb_priv = (urb_priv_t *)malloc (sizeof (urb_priv_t) + size * sizeof (td_t *));
	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_priv->length = size;
	urb_priv->ed = ed;	

	/* allocate the TDs (updating hash chains) */
//	spin_lock_irqsave (&usb_ed_lock, flags);
	for (i = 0; i < size; i++) { 
		urb_priv->td[i] = td_alloc (ohci);
		
		printf("TD[%d] MPUVA:0x%X    LBVA:0x%X\n",i,urb_priv->td[i],urb_priv->td[i]->td_dma);
		
		if (!urb_priv->td[i]) {
			urb_priv->length = i;
			urb_free_priv (ohci, urb_priv);
//			spin_unlock_irqrestore (&usb_ed_lock, flags);
			usb_dec_dev_use (urb->dev);	
			return -ENOMEM;
		}
	}	

	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
		urb_free_priv (ohci, urb_priv);
//		spin_unlock_irqrestore (&usb_ed_lock, flags);
		usb_dec_dev_use (urb->dev);	
		return -EINVAL;
	}
	
	/* allocate and claim bandwidth if needed; ISO
	 * needs start frame index if it was't provided.
	 */
	switch (usb_pipetype (pipe)) {
		case PIPE_ISOCHRONOUS:
			if (urb->transfer_flags & USB_ISO_ASAP) { 
				urb->start_frame = ((ed->state == ED_OPER)
					? (ed->last_iso + 1)
//					: (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
					: ((ohci->hcca->frame_no) + 10)) & 0xffff;
			}	
			/* FALLTHROUGH */
		case PIPE_INTERRUPT:
			if (urb->bandwidth == 0) {
				bustime = usb_check_bandwidth (urb->dev, urb);
			}
			if (bustime < 0) {
				urb_free_priv (ohci, urb_priv);
//				spin_unlock_irqrestore (&usb_ed_lock, flags);
				usb_dec_dev_use (urb->dev);	
				return bustime;
			}
			usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
#ifdef	DO_TIMEOUTS
			urb->timeout = 0;
#endif
	}

	urb->actual_length = 0;
	urb->hcpriv = urb_priv;
	urb->status = USB_ST_URB_PENDING;

	/* link the ed into a chain if is not already */
	if (ed->state != ED_OPER)
		ep_link (ohci, ed);

	/* fill the TDs and link it to the ed */
	td_submit_urb (urb);

#ifdef	DO_TIMEOUTS
	/* maybe add to ordered list of timeouts */
	if (urb->timeout) {
		struct list_head	*entry;

		// FIXME:  usb-uhci uses relative timeouts (like this),
		// while uhci uses absolute ones (probably better).
		// Pick one solution and change the affected drivers.
		urb->timeout += jiffies;

		list_for_each (entry, &ohci->timeout_list) {
			struct urb	*next_urb;

			next_urb = list_entry (entry, struct urb, urb_list);
			if (time_after_eq (urb->timeout, next_urb->timeout))
				break;
		}
		list_add (&urb->urb_list, entry);

		/* drive timeouts by SF (messy, but works) */
		writel (OHCI_INTR_SF, &ohci->regs->intrenable);	
		printf("SOF Enable -urb->timeout\n");
	}
#endif

//	spin_unlock_irqrestore (&usb_ed_lock, flags);

	printf("ED->hwHeadP:0x%X\thwTailP:0x%X\n\n",urb_priv->ed->hwHeadP,urb_priv->ed->hwTailP);//added by hcm
	return 0;	
}

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

/* deactivate all TDs and remove the private part of the URB */
/* interrupt callers must use async unlink mode */

static int sohci_unlink_urb (urb_t * urb)
{
//	unsigned long flags;
	ohci_t * ohci;
	
	if (!urb) /* just to be sure */ 
		return -EINVAL;
		
	if (!urb->dev || !urb->dev->bus)
		return -ENODEV;

	ohci = (ohci_t *) urb->dev->bus->hcpriv; 

⌨️ 快捷键说明

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