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

📄 usb-uhci.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			urb->start_frame = stop_limit;		//seamless linkage			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {				info("iso_find_start: gap in seamless isochronous scheduling");				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",					now, urb->start_frame, urb->number_of_packets, urb->pipe);				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!			}		}	}	else {		urb->start_frame &= 1023;		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {			dbg("iso_find_start: now between start_frame and end");			return -EAGAIN;		}	}	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */	if (limits)		return 0;	if (((urb->start_frame - start_limit) & 1023) < queued_size ||	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);		return -EAGAIN;	}	return 0;}/*-------------------------------------------------------------------*/// submits USB interrupt (ie. polling ;-) // ASAP-flag set implicitely// if period==0, the transfer is only done once_static int uhci_submit_int_urb (struct urb *urb){	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;	urb_priv_t *urb_priv = urb->hcpriv;	int nint, n;	uhci_desc_t *td;	int status, destination;	int info;	unsigned int pipe = urb->pipe;	if (urb->interval < 0 || urb->interval >= 256)		return -EINVAL;	if (urb->interval == 0)		nint = 0;	else {		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n		 {			if (urb->interval < n) {				urb->interval = n / 2;				break;			}		}		nint--;	}	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...	urb->number_of_packets = 1;	// INT allows only one packet	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))		return -EINVAL;	if (alloc_td (s, &td, UHCI_PTR_DEPTH))		return -ENOMEM;	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);	fill_td (td, status, info, urb_priv->transfer_buffer_dma);	list_add_tail (&td->desc_list, &urb_priv->desc_list);	queue_urb (s, urb);	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));	return 0;}/*-------------------------------------------------------------------*/_static int uhci_submit_iso_urb (struct urb *urb){	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;	urb_priv_t *urb_priv = urb->hcpriv;#ifdef ISO_SANITY_CHECK	int pipe=urb->pipe;	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));#endif	int n, ret, last=0;	uhci_desc_t *td, **tdm;	int status, destination;	unsigned long flags;	__save_flags(flags);	__cli();		      // Disable IRQs to schedule all ISO-TDs in time	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use		if (ret)		goto err;	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);	if (!tdm) {		ret = -ENOMEM;		goto err;	}	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 	// So, this solutions seems simpler...	for (n = 0; n < urb->number_of_packets; n++) {		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);		if (!urb->iso_frame_desc[n].length)			continue;  // allows ISO striping by setting length to zero in iso_descriptor#ifdef ISO_SANITY_CHECK		if(urb->iso_frame_desc[n].length > maxsze) {			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);			ret=-EINVAL;				}		else#endif		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {			int i;	// Cleanup allocated TDs			for (i = 0; i < n; n++)				if (tdm[i])					 delete_desc(s, tdm[i]);			kfree (tdm);			goto err;		}		last=n;		tdm[n] = td;	}	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);	// Queue all allocated TDs	for (n = 0; n < urb->number_of_packets; n++) {		td = tdm[n];		if (!td)			continue;					if (n  == last) {			status |= TD_CTRL_IOC;			queue_urb (s, urb);		}		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);		list_add_tail (&td->desc_list, &urb_priv->desc_list);			insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds	}	kfree (tdm);	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);	ret = 0;      err:	__restore_flags(flags);	return ret;}/*-------------------------------------------------------------------*/// returns: 0 (no transfer queued), urb* (this urb already queued) _static struct urb* search_dev_ep (uhci_t *s, struct urb *urb){	struct list_head *p;	struct urb *tmp;	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);	dbg("search_dev_ep:");	p=s->urb_list.next;	for (; p != &s->urb_list; p = p->next) {		tmp = list_entry (p, struct urb, urb_list);		dbg("urb: %p", tmp);		// we can accept this urb if it is not queued at this time 		// or if non-iso transfer requests should be scheduled for the same device and pipe		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||		    (urb == tmp)) {			return tmp;	// found another urb already queued for processing		}	}	return 0;}/*-------------------------------------------------------------------*/_static int uhci_submit_urb (struct urb *urb){	uhci_t *s;	urb_priv_t *urb_priv;	int ret = 0, type;	unsigned long flags;	struct urb *queued_urb=NULL;	int bustime;			if (!urb->dev || !urb->dev->bus)		return -ENODEV;	s = (uhci_t*) urb->dev->bus->hcpriv;	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));		if (!s->running)		return -ENODEV;		type = usb_pipetype (urb->pipe);	if (usb_pipedevice (urb->pipe) == s->rh.devnum)		return rh_submit_urb (urb);	/* virtual root hub */	// Sanity checks	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {				err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);		return -EMSGSIZE;	}	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {		err("uhci_submit_urb: Negative transfer length for urb %p", urb);		return -EINVAL;	}	usb_inc_dev_use (urb->dev);	spin_lock_irqsave (&s->urb_list_lock, flags);	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe	if (queued_urb) {		queue_dbg("found bulk urb %p\n", queued_urb);		if (( type != PIPE_BULK) ||		    ((type == PIPE_BULK) &&		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {			spin_unlock_irqrestore (&s->urb_list_lock, flags);			usb_dec_dev_use (urb->dev);			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);			return -ENXIO;	// urb already queued		}	}#ifdef DEBUG_SLAB	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);#else	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);#endif	if (!urb_priv) {		usb_dec_dev_use (urb->dev);		spin_unlock_irqrestore (&s->urb_list_lock, flags);		return -ENOMEM;	}	memset(urb_priv, 0, sizeof(urb_priv_t));	urb->hcpriv = urb_priv;	INIT_LIST_HEAD (&urb_priv->desc_list);	dbg("submit_urb: scheduling %p", urb);		if (type == PIPE_CONTROL)		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);	if (urb->transfer_buffer_length)		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,							       urb->transfer_buffer,							       urb->transfer_buffer_length,							       usb_pipein(urb->pipe) ?							       PCI_DMA_FROMDEVICE :							       PCI_DMA_TODEVICE);	if (type == PIPE_BULK) {			if (queued_urb) {			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;						((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;		}		atomic_inc (&s->avoid_bulk);		ret = uhci_submit_bulk_urb (urb, queued_urb);		atomic_dec (&s->avoid_bulk);		spin_unlock_irqrestore (&s->urb_list_lock, flags);	}	else {		spin_unlock_irqrestore (&s->urb_list_lock, flags);		switch (type) {		case PIPE_ISOCHRONOUS:						if (urb->bandwidth == 0) {      /* not yet checked/allocated */				if (urb->number_of_packets <= 0) {					ret = -EINVAL;					break;				}				bustime = usb_check_bandwidth (urb->dev, urb);				if (bustime < 0) 					ret = bustime;				else {					ret = uhci_submit_iso_urb(urb);					if (ret == 0)						usb_claim_bandwidth (urb->dev, urb, bustime, 1);				}			} else {        /* bandwidth is already set */				ret = uhci_submit_iso_urb(urb);			}			break;		case PIPE_INTERRUPT:			if (urb->bandwidth == 0) {      /* not yet checked/allocated */				bustime = usb_check_bandwidth (urb->dev, urb);				if (bustime < 0)					ret = bustime;				else {					ret = uhci_submit_int_urb(urb);					if (ret == 0)						usb_claim_bandwidth (urb->dev, urb, bustime, 0);				}			} else {        /* bandwidth is already set */				ret = uhci_submit_int_urb(urb);			}			break;		case PIPE_CONTROL:			ret = uhci_submit_control_urb (urb);			break;		default:			ret = -EINVAL;		}	}	dbg("submit_urb: scheduled with ret: %d", ret);		if (ret != 0) {		uhci_urb_dma_unmap(s, urb, urb_priv);		usb_dec_dev_use (urb->dev);#ifdef DEBUG_SLAB		kmem_cache_free(urb_priv_kmem, urb_priv);#else		kfree (urb_priv);#endif		return ret;	}	return 0;}// Checks for URB timeout and removes bandwidth reclamation if URB idles too long_static void uhci_check_timeouts(uhci_t *s){	struct list_head *p,*p2;	struct urb *urb;	int type;		p = s->urb_list.prev;		while (p != &s->urb_list) {		urb_priv_t *hcpriv;		p2 = p;		p = p->prev;		urb = list_entry (p2, struct urb, urb_list);		type = usb_pipetype (urb->pipe);		hcpriv = (urb_priv_t*)urb->hcpriv;				if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;			async_dbg("uhci_check_timeout: timeout for %p",urb);			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);		}#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))			disable_desc_loop(s, urb);#endif	}	s->timeout_check=jiffies;}/*------------------------------------------------------------------- Virtual Root Hub -------------------------------------------------------------------*/_static __u8 root_hub_dev_des[] ={	0x12,			/*  __u8  bLength; */	0x01,			/*  __u8  bDescriptorType; Device */	0x00,			/*  __u16 bcdUSB; v1.0 */	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; */};/* Configuration descriptor */_static __u8 root_hub_config_des[] ={	0x09,			/*  __u8  bLength; */	0x02,			/*  __u8  bDescriptorType; Configuration */	0x19,			/*  __u16 wTotalLength; */	0x00,	0x01,			/*  __u8  bNumInterfaces; */	0x01,			/*  __u8  bConfigurationValue; */	0x00,			/*  __u8  iConfiguration; */	0x40,			/*  __u8  bmAttributes; 				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */	0x00,			/*  __u8  MaxPower; */     /* interface */	0x09,			/*  __u8  if_bLength; */	0x04,			/*  __u8  if_bDescriptorType; Interface */	0x00,			/*  __u8  if_bInterfaceNumber; */	0x00,			/*  __u8  if_bAlternateSetting; */	0x01,			/*  __u8  if_bNumEndpoints; */	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,			/*  __u8  if_bInterfaceSubClass; */	0x00,			/*  __u8  if_bInterfaceProtocol; */	0x00,			/*  __u8  if_iInterface; */     /* endpoint */	0x07,			/*  __u8  ep_bLength; */	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */	0x03,			/*  __u8  ep_bmAttributes; Interrupt */	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */	0x00,	0xff			/*  __u8  ep_bInterval; 255 ms */};_static __u8 root_hub_hub_des[] =

⌨️ 快捷键说明

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