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

📄 irda-usb.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Generate min turn time. FIXME: can we do better than this? */	/* Trying to a turnaround time at this level is trying to measure	 * processor clock cycle with a wrist-watch, approximate at best...	 *	 * What we know is the last time we received a frame over USB.	 * Due to latency over USB that depend on the USB load, we don't	 * know when this frame was received over IrDA (a few ms before ?)	 * Then, same story for our outgoing frame...	 *	 * In theory, the USB dongle is supposed to handle the turnaround	 * by itself (spec 1.0, chater 4, page 6). Who knows ??? That's	 * why this code is enabled only for dongles that doesn't meet	 * the spec.	 * Jean II */	if (self->capability & IUC_NO_TURN) {		mtt = irda_get_mtt(skb);		if (mtt) {			int diff;			do_gettimeofday(&self->now);			diff = self->now.tv_usec - self->stamp.tv_usec;#ifdef IU_USB_MIN_RTT			/* Factor in USB delays -> Get rid of udelay() that			 * would be lost in the noise - Jean II */			diff += IU_USB_MIN_RTT;#endif /* IU_USB_MIN_RTT */			if (diff < 0)				diff += 1000000;		        /* Check if the mtt is larger than the time we have			 * already used by all the protocol processing			 */			if (mtt > diff) {				mtt -= diff;				if (mtt > 1000)					mdelay(mtt/1000);				else					udelay(mtt);			}		}	}		/* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */	if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {		WARNING(__FUNCTION__ "(), failed Tx URB\n");		self->stats.tx_errors++;		/* Let USB recover : We will catch that in the watchdog */		/*netif_start_queue(netdev);*/	} else {		/* Increment packet stats */		self->stats.tx_packets++;                self->stats.tx_bytes += skb->len;				netdev->trans_start = jiffies;	}	spin_unlock_irqrestore(&self->lock, flags);		return 0;drop:	/* Drop silently the skb and exit */	dev_kfree_skb(skb);	spin_unlock_irqrestore(&self->lock, flags);	return 0;}/*------------------------------------------------------------------*//* * Note : this function will be called only for tx_urb... */static void write_bulk_callback(struct urb *urb){	unsigned long flags;	struct sk_buff *skb = urb->context;	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;		IRDA_DEBUG(2, __FUNCTION__ "()\n");	/* We should always have a context */	if (self == NULL) {		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");		return;	}	/* Free up the skb */	dev_kfree_skb_any(skb);	urb->context = NULL;	/* Check for timeout and other USB nasties */	if (urb->status != 0) {		/* I get a lot of -ECONNABORTED = -103 here - Jean II */		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);		/* Don't do anything here, that might confuse the USB layer,		 * and we could go in recursion and blow the kernel stack...		 * Instead, we will wait for irda_usb_net_timeout(), the		 * network layer watchdog, to fix the situation.		 * Jean II */		/* A reset of the dongle might be welcomed here - Jean II */		return;	}	/* urb is now available */	//urb->status = 0; -> tested above	/* Make sure we read self->present properly */	spin_lock_irqsave(&self->lock, flags);	/* If the network is closed, stop everything */	if ((!self->netopen) || (!self->present)) {		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");		spin_unlock_irqrestore(&self->lock, flags);		return;	}	/* If we need to change the speed or xbofs, do it now */	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {		IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n");		irda_usb_change_speed_xbofs(self);	} else {		/* Otherwise, allow the stack to send more packets */		netif_wake_queue(self->netdev);	}	spin_unlock_irqrestore(&self->lock, flags);}/*------------------------------------------------------------------*//* * Watchdog timer from the network layer. * After a predetermined timeout, if we don't give confirmation that * the packet has been sent (i.e. no call to netif_wake_queue()), * the network layer will call this function. * Note that URB that we submit have also a timeout. When the URB timeout * expire, the normal URB callback is called (write_bulk_callback()). */static void irda_usb_net_timeout(struct net_device *netdev){	unsigned long flags;	struct irda_usb_cb *self = netdev->priv;	struct urb *urb;	int	done = 0;	/* If we have made any progress */	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");	/* Protect us from USB callbacks, net Tx and else. */	spin_lock_irqsave(&self->lock, flags);	if ((!self) || (!self->present)) {		WARNING(__FUNCTION__ "(), device not present!\n");		netif_stop_queue(netdev);		spin_unlock_irqrestore(&self->lock, flags);		return;	}	/* Check speed URB */	urb = self->speed_urb;	if (urb->status != 0) {		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);		switch (urb->status) {		case -EINPROGRESS:			usb_unlink_urb(urb);			/* Note : above will  *NOT* call netif_wake_queue()			 * in completion handler, we will come back here.			 * Jean II */			done = 1;			break;		case -ECONNABORTED:		/* -103 */		case -ECONNRESET:		/* -104 */		case -ETIMEDOUT:		/* -110 */		case -ENOENT:			/* -2 (urb unlinked by us)  */		default:			/* ??? - Play safe */			urb->status = 0;			netif_wake_queue(self->netdev);			done = 1;			break;		}	}	/* Check Tx URB */	urb = self->tx_urb;	if (urb->status != 0) {		struct sk_buff *skb = urb->context;		IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);		/* Increase error count */		self->stats.tx_errors++;#ifdef IU_BUG_KICK_TIMEOUT		/* Can't be a bad idea to reset the speed ;-) - Jean II */		if(self->new_speed == -1)			self->new_speed = self->speed;		if(self->new_xbofs == -1)			self->new_xbofs = self->xbofs;		irda_usb_change_speed_xbofs(self);#endif /* IU_BUG_KICK_TIMEOUT */		switch (urb->status) {		case -EINPROGRESS:			usb_unlink_urb(urb);			/* Note : above will  *NOT* call netif_wake_queue()			 * in completion handler, because urb->status will			 * be -ENOENT. We will fix that at the next watchdog,			 * leaving more time to USB to recover...			 * Also, we are in interrupt, so we need to have			 * USB_ASYNC_UNLINK to work properly...			 * Jean II */			done = 1;			break;		case -ECONNABORTED:		/* -103 */		case -ECONNRESET:		/* -104 */		case -ETIMEDOUT:		/* -110 */		case -ENOENT:			/* -2 (urb unlinked by us)  */		default:			/* ??? - Play safe */			if(skb != NULL) {				dev_kfree_skb_any(skb);				urb->context = NULL;			}			urb->status = 0;			netif_wake_queue(self->netdev);			done = 1;			break;		}	}	spin_unlock_irqrestore(&self->lock, flags);	/* Maybe we need a reset */	/* Note : Some drivers seem to use a usb_set_interface() when they	 * need to reset the hardware. Hum...	 */	/* if(done == 0) */}/************************* RECEIVE ROUTINES *************************//* * Receive packets from the USB layer stack and pass them to the IrDA stack. * Try to work around USB failures... *//* * Note : * Some of you may have noticed that most dongle have an interrupt in pipe * that we don't use. Here is the little secret... * When we hang a Rx URB on the bulk in pipe, it generates some USB traffic * in every USB frame. This is unnecessary overhead. * The interrupt in pipe will generate an event every time a packet is * received. Reading an interrupt pipe adds minimal overhead, but has some * latency (~1ms). * If we are connected (speed != 9600), we want to minimise latency, so * we just always hang the Rx URB and ignore the interrupt. * If we are not connected (speed == 9600), there is usually no Rx traffic, * and we want to minimise the USB overhead. In this case we should wait * on the interrupt pipe and hang the Rx URB only when an interrupt is * received. * Jean II *//*------------------------------------------------------------------*//* * Submit a Rx URB to the USB layer to handle reception of a frame * * Important note : * The function process_urb() in usb-uhci.c contains the following code : * >	urb->complete ((struct urb *) urb); * >	// Re-submit the URB if ring-linked * >	if (is_ring && (urb->status != -ENOENT) && !contains_killed) { * >		urb->dev=usb_dev; * >		uhci_submit_urb (urb); * >	} * The way I see it is that if we submit more than one Rx URB at a * time, the Rx URB can be automatically re-submitted after the * completion handler is called. * We make sure to disable this feature by setting urb->next to NULL * * My take is that it's a questionable feature, and quite difficult * to control and to make work effectively. * The outcome (re-submited or not) depend on various complex * test ('is_ring' and 'contains_killed'), and the completion handler * don't have this information, so basically the driver has no way * to know if URB are resubmitted or not. Yuck ! * If everything is perfect, it's cool, but the problem is when * an URB is killed (timeout, call to unlink_urb(), ...), things get * messy... * The other problem is that this scheme deal only with the URB * and ignore everything about the associated buffer. So, it would * resubmit URB even if the buffer is still in use or non-existent. * On the other hand, submitting ourself in the completion callback * is quite trivial and work well (this function). * Moreover, this scheme doesn't allow to have an idle URB, which is * necessary to overcome some URB failures. * * Jean II */static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb){	struct irda_skb_cb *cb;	int ret;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	/* Check that we have an urb */	if (!urb) {		WARNING(__FUNCTION__ "(), Bug : urb == NULL\n");		return;	}	/* Allocate new skb if it has not been recycled */	if (!skb) {		skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1);		if (!skb) {			/* If this ever happen, we are in deep s***.			 * Basically, the Rx path will stop... */			WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n");			return;		}	} else  {		/* Reset recycled skb */		skb->data = skb->tail = skb->head;		skb->len = 0;	}	/* Make sure IP header get aligned (IrDA header is 5 bytes ) */	skb_reserve(skb, 1);	/* Save ourselves */	cb = (struct irda_skb_cb *) skb->cb;	cb->context = self;	/* Reinitialize URB */	FILL_BULK_URB(urb, self->usbdev, 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 		      skb->data, skb->truesize,                      irda_usb_receive, skb);	urb->transfer_flags = USB_QUEUE_BULK;	/* Note : unlink *must* be synchronous because of the code in 	 * irda_usb_net_close() -> free the skb - Jean II */	urb->status = 0;	urb->next = NULL;	/* Don't auto resubmit URBs */	/* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */	ret = usb_submit_urb(urb, GFP_ATOMIC);	if (ret) {		/* If this ever happen, we are in deep s***.		 * Basically, the Rx path will stop... */		WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret);	}}/*------------------------------------------------------------------*//* * Function irda_usb_receive(urb) * *     Called by the USB subsystem when a frame has been received * */static void irda_usb_receive(struct urb *urb) {	struct sk_buff *skb = (struct sk_buff *) urb->context;	struct irda_usb_cb *self; 	struct irda_skb_cb *cb;	struct sk_buff *new;		IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length);		/* Find ourselves */	cb = (struct irda_skb_cb *) skb->cb;	ASSERT(cb != NULL, return;);	self = (struct irda_usb_cb *) cb->context;	ASSERT(self != NULL, return;);	/* If the network is closed or the device gone, stop everything */	if ((!self->netopen) || (!self->present)) {		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n");		/* Don't re-submit the URB : will stall the Rx path */		return;	}		/* Check the status */	if (urb->status != 0) {		switch (urb->status) {		case -EILSEQ:			self->stats.rx_errors++;			self->stats.rx_crc_errors++;				break;		case -ECONNRESET:		/* -104 */			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->transfer_flags);			/* uhci_cleanup_unlink() is going to kill the Rx			 * URB just after we return. No problem, at this			 * point the URB will be idle ;-) - Jean II */			break;		default:			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags);			break;		}		goto done;	}		/* Check for empty frames */	if (urb->actual_length <= USB_IRDA_HEADER) {		WARNING(__FUNCTION__ "(), empty frame!\n");		goto done;	}	/*  	 * Remember the time we received this frame, so we can	 * reduce the min turn time a bit since we will know	 * how much time we have used for protocol processing	 */        do_gettimeofday(&self->stamp);	/* Fix skb, and remove USB-IrDA header */	skb_put(skb, urb->actual_length);	skb_pull(skb, USB_IRDA_HEADER);	/* Don't waste a lot of memory on small IrDA frames */	if (skb->len < RX_COPY_THRESHOLD) {		new = dev_alloc_skb(skb->len+1);

⌨️ 快捷键说明

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