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

📄 irda-usb.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* 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, USB_IRDA_HEADER);	/* 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);	netif_rx(dataskb);	/* Keep stats up to date */	self->stats.rx_bytes += dataskb->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. Another time... Jean II */	/* Submit the idle URB to replace the URB we've just received */	irda_usb_submit(self, skb, self->idle_rx_urb);	/* Recycle Rx URB : Now, the idle URB is the present one */	urb->context = NULL;	self->idle_rx_urb = urb;}/*------------------------------------------------------------------*//* * Callbak from IrDA layer. IrDA wants to know if we have * started receiving anything. */static int irda_usb_is_receiving(struct irda_usb_cb *self){	/* Note : because of the way UHCI works, it's almost impossible	 * to get this info. The Controller DMA directly to memory and	 * signal only when the whole frame is finished. To know if the	 * first TD of the URB has been filled or not seems hard work...	 *	 * The other solution would be to use the "receiving" command	 * on the default decriptor with a usb_control_msg(), but that	 * would add USB traffic and would return result only in the	 * next USB frame (~1ms).	 *	 * I've been told that current dongles send status info on their	 * interrupt endpoint, and that's what the Windows driver uses	 * to know this info. Unfortunately, this is not yet in the spec...	 *	 * Jean II	 */	return 0; /* For now */}/********************** IRDA DEVICE CALLBACKS **********************//* * Main calls from the IrDA/Network subsystem. * Mostly registering a new irda-usb device and removing it.... * We only deal with the IrDA side of the business, the USB side will * be dealt with below... *//*------------------------------------------------------------------*//* * Function irda_usb_net_open (dev) * *    Network device is taken up. Usually this is done by "ifconfig irda0 up"  *    * Note : don't mess with self->netopen - Jean II */static int irda_usb_net_open(struct net_device *netdev){	struct irda_usb_cb *self;	char	hwname[16];	int i;		IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	ASSERT(netdev != NULL, return -1;);	self = (struct irda_usb_cb *) netdev->priv;	ASSERT(self != NULL, return -1;);	/* Can only open the device if it's there */	if(!self->present) {		WARNING("%s(), device not present!\n", __FUNCTION__);		return -1;	}	/* Initialise default speed and xbofs value	 * (IrLAP will change that soon) */	self->speed = -1;	self->xbofs = -1;	self->new_speed = -1;	self->new_xbofs = -1;	/* To do *before* submitting Rx urbs and starting net Tx queue	 * Jean II */	self->netopen = 1;	/* 	 * Now that everything should be initialized properly,	 * Open new IrLAP layer instance to take care of us...	 * Note : will send immediately a speed change...	 */	sprintf(hwname, "usb#%d", self->usbdev->devnum);	self->irlap = irlap_open(netdev, &self->qos, hwname);	ASSERT(self->irlap != NULL, return -1;);	/* Allow IrLAP to send data to us */	netif_start_queue(netdev);	/* We submit all the Rx URB except for one that we keep idle.	 * Need to be initialised before submitting other USBs, because	 * in some cases as soon as we submit the URBs the USB layer	 * will trigger a dummy receive - Jean II */	self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS];	self->idle_rx_urb->context = NULL;	/* Now that we can pass data to IrLAP, allow the USB layer	 * to send us some data... */	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) {		struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);		if (!skb) {			/* If this ever happen, we are in deep s***.			 * Basically, we can't start the Rx path... */			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);			return -1;		}		//skb_reserve(newskb, USB_IRDA_HEADER - 1);		irda_usb_submit(self, skb, self->rx_urb[i]);	}	/* Ready to play !!! */	return 0;}/*------------------------------------------------------------------*//* * Function irda_usb_net_close (self) * *    Network device is taken down. Usually this is done by  *    "ifconfig irda0 down"  */static int irda_usb_net_close(struct net_device *netdev){	struct irda_usb_cb *self;	int	i;	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	ASSERT(netdev != NULL, return -1;);	self = (struct irda_usb_cb *) netdev->priv;	ASSERT(self != NULL, return -1;);	/* Clear this flag *before* unlinking the urbs and *before*	 * stopping the network Tx queue - Jean II */	self->netopen = 0;	/* Stop network Tx queue */	netif_stop_queue(netdev);	/* Deallocate all the Rx path buffers (URBs and skb) */	for (i = 0; i < IU_MAX_RX_URBS; i++) {		struct urb *urb = self->rx_urb[i];		struct sk_buff *skb = (struct sk_buff *) urb->context;		/* Cancel the receive command */		usb_unlink_urb(urb);		/* The skb is ours, free it */		if(skb) {			dev_kfree_skb(skb);			urb->context = NULL;		}	}	/* Cancel Tx and speed URB - need to be synchronous to avoid races */	self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;	usb_kill_urb(self->tx_urb);	self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;	usb_kill_urb(self->speed_urb);	/* Stop and remove instance of IrLAP */	if (self->irlap)		irlap_close(self->irlap);	self->irlap = NULL;	return 0;}/*------------------------------------------------------------------*//* * IOCTLs : Extra out-of-band network commands... */static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	unsigned long flags;	struct if_irda_req *irq = (struct if_irda_req *) rq;	struct irda_usb_cb *self;	int ret = 0;	ASSERT(dev != NULL, return -1;);	self = dev->priv;	ASSERT(self != NULL, return -1;);	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);	switch (cmd) {	case SIOCSBANDWIDTH: /* Set bandwidth */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		/* Protect us from USB callbacks, net watchdog and else. */		spin_lock_irqsave(&self->lock, flags);		/* Check if the device is still there */		if(self->present) {			/* Set the desired speed */			self->new_speed = irq->ifr_baudrate;			irda_usb_change_speed_xbofs(self);		}		spin_unlock_irqrestore(&self->lock, flags);		break;	case SIOCSMEDIABUSY: /* Set media busy */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		/* Check if the IrDA stack is still there */		if(self->netopen)			irda_device_set_media_busy(self->netdev, TRUE);		break;	case SIOCGRECEIVING: /* Check if we are receiving right now */		irq->ifr_receiving = irda_usb_is_receiving(self);		break;	default:		ret = -EOPNOTSUPP;	}		return ret;}/*------------------------------------------------------------------*//* * Get device stats (for /proc/net/dev and ifconfig) */static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev){	struct irda_usb_cb *self = dev->priv;	return &self->stats;}/********************* IRDA CONFIG SUBROUTINES *********************//* * Various subroutines dealing with IrDA and network stuff we use to * configure and initialise each irda-usb instance. * These functions are used below in the main calls of the driver... *//*------------------------------------------------------------------*//* * Set proper values in the IrDA QOS structure */static inline void irda_usb_init_qos(struct irda_usb_cb *self){	struct irda_class_desc *desc;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);		desc = self->irda_desc;		/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&self->qos);	/* See spec section 7.2 for meaning.	 * Values are little endian (as most USB stuff), the IrDA stack	 * use it in native order (see parameters.c). - Jean II */	self->qos.baud_rate.bits       = le16_to_cpu(desc->wBaudRate);	self->qos.min_turn_time.bits   = desc->bmMinTurnaroundTime;	self->qos.additional_bofs.bits = desc->bmAdditionalBOFs;	self->qos.window_size.bits     = desc->bmWindowSize;	self->qos.data_size.bits       = desc->bmDataSize;	IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", 		__FUNCTION__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);	/* Don't always trust what the dongle tell us */	if(self->capability & IUC_SIR_ONLY)		self->qos.baud_rate.bits	&= 0x00ff;	if(self->capability & IUC_SMALL_PKT)		self->qos.data_size.bits	 = 0x07;	if(self->capability & IUC_NO_WINDOW)		self->qos.window_size.bits	 = 0x01;	if(self->capability & IUC_MAX_WINDOW)		self->qos.window_size.bits	 = 0x7f;	if(self->capability & IUC_MAX_XBOFS)		self->qos.additional_bofs.bits	 = 0x01;#if 1	/* Module parameter can override the rx window size */	if (qos_mtt_bits)		self->qos.min_turn_time.bits = qos_mtt_bits;#endif	    	/* 	 * Note : most of those values apply only for the receive path,	 * the transmit path will be set differently - Jean II 	 */	irda_qos_bits_to_value(&self->qos);}/*------------------------------------------------------------------*//* * Initialise the network side of the irda-usb instance * Called when a new USB instance is registered in irda_usb_probe() */static inline int irda_usb_open(struct irda_usb_cb *self){	struct net_device *netdev = self->netdev;	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	irda_usb_init_qos(self);	/* Override the network functions we need to use */	netdev->hard_start_xmit = irda_usb_hard_xmit;	netdev->tx_timeout	= irda_usb_net_timeout;	netdev->watchdog_timeo  = 250*HZ/1000;	/* 250 ms > USB timeout */	netdev->open            = irda_usb_net_open;	netdev->stop            = irda_usb_net_close;	netdev->get_stats	= irda_usb_net_get_stats;	netdev->do_ioctl        = irda_usb_net_ioctl;	return register_netdev(netdev);}/*------------------------------------------------------------------*//* * Cleanup the network side of the irda-usb instance * Called when a USB instance is removed in irda_usb_disconnect() */static inline void irda_usb_close(struct irda_usb_cb *self){	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	/* Remove netdevice */	unregister_netdev(self->netdev);	/* Remove the speed buffer */	if (self->speed_buff != NULL) {		kfree(self->speed_buff);		self->speed_buff = NULL;	}}/********************** USB CONFIG SUBROUTINES **********************//* * Various subroutines dealing with USB stuff we use to configure and * initialise each irda-usb instance. * These functions are used below in the main calls of the driver... *//*------------------------------------------------------------------*//* * Function irda_usb_parse_endpoints(dev, ifnum) * *    Parse the various endpoints and find the one we need. * * The endpoint are the pipes used to communicate with the USB device. * The spec defines 2 endpoints of type bulk transfer, one in, and one out. * These are used to pass frames back and forth with the dongle. * Most dongle have also an interrupt endpoint, that will be probably * documented in the next spec... */static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_host_endpoint *endpoint, int ennum){	int i;		/* Endpoint index in table */

⌨️ 快捷键说明

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