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

📄 irda-usb.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
{	struct urb *urb = (struct urb *) data;	struct sk_buff *skb = (struct sk_buff *) urb->context;	struct irda_usb_cb *self; 	struct irda_skb_cb *cb;	struct urb *next_urb;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	/* 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;);	/* Same stuff as when Rx is done, see above... */	next_urb = self->idle_rx_urb;	urb->context = NULL;	self->idle_rx_urb = urb;	irda_usb_submit(self, skb, next_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 */}#define STIR421X_PATCH_PRODUCT_VER     "Product Version: "#define STIR421X_PATCH_STMP_TAG        "STMP"#define STIR421X_PATCH_CODE_OFFSET     512 /* patch image starts before here *//* marks end of patch file header (PC DOS text file EOF character) */#define STIR421X_PATCH_END_OF_HDR_TAG  0x1A#define STIR421X_PATCH_BLOCK_SIZE      1023/* * Function stir421x_fwupload (struct irda_usb_cb *self, *                             unsigned char *patch, *                             const unsigned int patch_len) * *   Upload firmware code to SigmaTel 421X IRDA-USB dongle */static int stir421x_fw_upload(struct irda_usb_cb *self,			     unsigned char *patch,			     const unsigned int patch_len){        int ret = -ENOMEM;        int actual_len = 0;        unsigned int i;        unsigned int block_size = 0;        unsigned char *patch_block;        patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL);	if (patch_block == NULL)		return -ENOMEM;	/* break up patch into 1023-byte sections */	for (i = 0; i < patch_len; i += block_size) {		block_size = patch_len - i;		if (block_size > STIR421X_PATCH_BLOCK_SIZE)			block_size = STIR421X_PATCH_BLOCK_SIZE;		/* upload the patch section */		memcpy(patch_block, patch + i, block_size);		ret = usb_bulk_msg(self->usbdev,				   usb_sndbulkpipe(self->usbdev,						   self->bulk_out_ep),				   patch_block, block_size,				   &actual_len, msecs_to_jiffies(500));		IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n",			   __FUNCTION__, actual_len, ret);		if (ret < 0)			break;	}	kfree(patch_block);        return ret; }/* * Function stir421x_patch_device(struct irda_usb_cb *self) * * Get a firmware code from userspase using hotplug request_firmware() call  */static int stir421x_patch_device(struct irda_usb_cb *self){        unsigned int i;        int ret;        char stir421x_fw_name[11];        const struct firmware *fw;        unsigned char *fw_version_ptr; /* pointer to version string */	unsigned long fw_version = 0;        /*         * Known firmware patch file names for STIR421x dongles         * are "42101001.sb" or "42101002.sb"         */        sprintf(stir421x_fw_name, "4210%4X.sb",                self->usbdev->descriptor.bcdDevice);        ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev);        if (ret < 0)                return ret;        /* We get a patch from userspace */        IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",                     __FUNCTION__, stir421x_fw_name, fw->size);        ret = -EINVAL;	/* Get the bcd product version */        if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER,                    sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) {                fw_version_ptr = fw->data +			sizeof(STIR421X_PATCH_PRODUCT_VER) - 1;                /* Let's check if the product version is dotted */                if (fw_version_ptr[3] == '.' &&		    fw_version_ptr[7] == '.') {			unsigned long major, minor, build;			major = simple_strtoul(fw_version_ptr, NULL, 10);			minor = simple_strtoul(fw_version_ptr + 4, NULL, 10);			build = simple_strtoul(fw_version_ptr + 8, NULL, 10);			fw_version = (major << 12)				+ (minor << 8)				+ ((build / 10) << 4)				+ (build % 10);			IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n",                                   __FUNCTION__, fw_version);                }        }        if (self->usbdev->descriptor.bcdDevice == fw_version) {                /*		 * If we're here, we've found a correct patch                 * The actual image starts after the "STMP" keyword                 * so forward to the firmware header tag                 */                for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG)			     && (i < fw->size); i++) ;                /* here we check for the out of buffer case */                if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i])                    && (i < STIR421X_PATCH_CODE_OFFSET)) {                        if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,                                    sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {				/* We can upload the patch to the target */				i += sizeof(STIR421X_PATCH_STMP_TAG);                                ret = stir421x_fw_upload(self, &fw->data[i],							 fw->size - i);                        }                }        }        release_firmware(fw);        return ret;}/********************** 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__);	IRDA_ASSERT(netdev != NULL, return -1;);	self = (struct irda_usb_cb *) netdev->priv;	IRDA_ASSERT(self != NULL, return -1;);	/* Can only open the device if it's there */	if(!self->present) {		IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);		return -1;	}	if(self->needspatch) {		IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ;		return -EIO ;	}	/* 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);	IRDA_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... */			IRDA_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__);	IRDA_ASSERT(netdev != NULL, return -1;);	self = (struct irda_usb_cb *) netdev->priv;	IRDA_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);	/* Kill defered Rx URB */	del_timer(&self->rx_defer_timer);	/* Deallocate all the Rx path buffers (URBs and skb) */	for (i = 0; i < self->max_rx_urb; i++) {		struct urb *urb = self->rx_urb[i];		struct sk_buff *skb = (struct sk_buff *) urb->context;		/* Cancel the receive command */		usb_kill_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 */	usb_kill_urb(self->tx_urb);	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;	IRDA_ASSERT(dev != NULL, return -1;);	self = dev->priv;	IRDA_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 */

⌨️ 快捷键说明

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