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

📄 irda-usb.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* 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 the usec counter did wraparound, the diff will			 * go negative (tv_usec is a long), so we need to			 * correct it by one second. Jean II */			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))) {		IRDA_WARNING("%s(), failed Tx URB\n", __FUNCTION__);		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 err;		/* Usually 1 */}/*------------------------------------------------------------------*//* * 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, "%s()\n", __FUNCTION__);	/* We should always have a context */	IRDA_ASSERT(self != NULL, return;);	/* We should always be called for the speed URB */	IRDA_ASSERT(urb == self->tx_urb, 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, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, 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, "%s(), Network is gone...\n", __FUNCTION__);		spin_unlock_irqrestore(&self->lock, flags);		return;	}	/* If changes to speed or xbofs is pending... */	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {		if ((self->new_speed != self->speed) ||		    (self->new_xbofs != self->xbofs)) {			/* We haven't changed speed yet (because of			 * IUC_SPEED_BUG), so do it now - Jean II */			IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__);			irda_usb_change_speed_xbofs(self);		} else {			/* New speed and xbof is now commited in hardware */			self->new_speed = -1;			self->new_xbofs = -1;			/* Done, waiting for next packet */			netif_wake_queue(self->netdev);		}	} 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, "%s(), Network layer thinks we timed out!\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	/* Protect us from USB callbacks, net Tx and else. */	spin_lock_irqsave(&self->lock, flags);	/* self->present *MUST* be read under spinlock */	if (!self->present) {		IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);		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 -ECONNRESET:		case -ENOENT:			/* 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...			 * Jean II */			done = 1;			break;		case -ECONNRESET:		case -ENOENT:			/* 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 * * Note : don't read the above as what we are currently doing, but as * something we could do with KC dongle. Also don't forget that the * interrupt pipe is not part of the original standard, so this would * need to be optional... * Jean II *//*------------------------------------------------------------------*//* * Submit a Rx URB to the USB layer to handle reception of a frame * Mostly called by the completion callback of the previous URB. * * 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, "%s()\n", __FUNCTION__);	/* This should never happen */	IRDA_ASSERT(skb != NULL, return;);	IRDA_ASSERT(urb != NULL, return;);	/* Save ourselves in the skb */	cb = (struct irda_skb_cb *) skb->cb;	cb->context = self;	/* Reinitialize URB */	usb_fill_bulk_urb(urb, self->usbdev, 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 		      skb->data, IRDA_SKB_MAX_MTU,                      irda_usb_receive, skb);	urb->status = 0;	/* 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... */		IRDA_WARNING("%s(), Failed to submit Rx URB %d\n",			     __FUNCTION__, 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 *newskb;	struct sk_buff *dataskb;	struct urb *next_urb;	unsigned int len, docopy;	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);		/* Find ourselves */	cb = (struct irda_skb_cb *) skb->cb;	IRDA_ASSERT(cb != NULL, return;);	self = (struct irda_usb_cb *) cb->context;	IRDA_ASSERT(self != NULL, return;);	/* If the network is closed or the device gone, stop everything */	if ((!self->netopen) || (!self->present)) {		IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__);		/* 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_crc_errors++;				/* Also precursor to a hot-unplug on UHCI. */			/* Fallthrough... */		case -ECONNRESET:			/* Random error, if I remember correctly */			/* 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 */		case -ESHUTDOWN:			/* That's usually a hot-unplug. Submit will fail... */		case -ETIME:			/* Usually precursor to a hot-unplug on OHCI. */		default:			self->stats.rx_errors++;			IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags);			break;		}		/* If we received an error, we don't want to resubmit the		 * Rx URB straight away but to give the USB layer a little		 * bit of breathing room.		 * We are in the USB thread context, therefore there is a		 * danger of recursion (new URB we submit fails, we come		 * back here).		 * With recent USB stack (2.6.15+), I'm seeing that on		 * hot unplug of the dongle...		 * Lowest effective timer is 10ms...		 * Jean II */		self->rx_defer_timer.function = &irda_usb_rx_defer_expired;		self->rx_defer_timer.data = (unsigned long) urb;		mod_timer(&self->rx_defer_timer, jiffies + (10 * HZ / 1000));		return;	}		/* Check for empty frames */	if (urb->actual_length <= self->header_length) {		IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__);		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);	/* Check if we need to copy the data to a new skb or not.	 * For most frames, we use ZeroCopy and pass the already	 * allocated skb up the stack.	 * If the frame is small, it is more efficient to copy it	 * to save memory (copy will be fast anyway - that's	 * called Rx-copy-break). Jean II */	docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);	/* Allocate a new skb */	if (self->capability & IUC_STIR421X)		newskb = dev_alloc_skb(docopy ? urb->actual_length :				       IRDA_SKB_MAX_MTU +				       USB_IRDA_STIR421X_HEADER);	else		newskb = dev_alloc_skb(docopy ? urb->actual_length :				       IRDA_SKB_MAX_MTU);	if (!newskb)  {		self->stats.rx_dropped++;		/* We could deliver the current skb, but this would stall		 * the Rx path. Better drop the packet... Jean II */		goto done;  	}	/* Make sure IP header get aligned (IrDA header is 5 bytes) */	/* But IrDA-USB header is 1 byte. Jean II */	//skb_reserve(newskb, USB_IRDA_HEADER - 1);	if(docopy) {		/* Copy packet, so we can recycle the original */		memcpy(newskb->data, skb->data, urb->actual_length);		/* Deliver this new skb */		dataskb = newskb;		/* And hook the old skb to the URB		 * Note : we don't need to "clean up" the old skb,		 * as we never touched it. Jean II */	} else {		/* We are using ZeroCopy. Deliver old skb */		dataskb = skb;		/* And hook the new skb to the URB */		skb = newskb;	}	/* Set proper length on skb & remove USB-IrDA header */	skb_put(dataskb, urb->actual_length);	skb_pull(dataskb, self->header_length);	/* Ask the networking layer to queue the packet for the IrDA stack */	dataskb->dev = self->netdev;	dataskb->mac.raw  = dataskb->data;	dataskb->protocol = htons(ETH_P_IRDA);	len = dataskb->len;	netif_rx(dataskb);	/* Keep stats up to date */	self->stats.rx_bytes += len;	self->stats.rx_packets++;	self->netdev->last_rx = jiffies;done:	/* Note : at this point, the URB we've just received (urb)	 * is still referenced by the USB layer. For example, if we	 * have received a -ECONNRESET, uhci_cleanup_unlink() will	 * continue to process it (in fact, cleaning it up).	 * If we were to submit this URB, disaster would ensue.	 * Therefore, we submit our idle URB, and put this URB in our	 * idle slot....	 * Jean II */	/* Note : with this scheme, we could submit the idle URB before	 * processing the Rx URB. I don't think it would buy us anything as	 * we are running in the USB thread context. Jean II */	next_urb = self->idle_rx_urb;	/* Recycle Rx URB : Now, the idle URB is the present one */	urb->context = NULL;	self->idle_rx_urb = urb;	/* Submit the idle URB to replace the URB we've just received.	 * Do it last to avoid race conditions... Jean II */	irda_usb_submit(self, skb, next_urb);}/*------------------------------------------------------------------*//* * In case of errors, we want the USB layer to have time to recover. * Now, it is time to resubmit ouur Rx URB... */static void irda_usb_rx_defer_expired(unsigned long data)

⌨️ 快捷键说明

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