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

📄 irda-usb.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	kfree(self->speed_buff);	self->speed_buff = NULL;	kfree(self->tx_buff);	self->tx_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 */			/* Init : no endpoints */	self->bulk_in_ep = 0;	self->bulk_out_ep = 0;	self->bulk_int_ep = 0;	/* Let's look at all those endpoints */	for(i = 0; i < ennum; i++) {		/* All those variables will get optimised by the compiler,		 * so let's aim for clarity... - Jean II */		__u8 ep;	/* Endpoint address */		__u8 dir;	/* Endpoint direction */		__u8 attr;	/* Endpoint attribute */		__u16 psize;	/* Endpoint max packet size in bytes */		/* Get endpoint address, direction and attribute */		ep = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;		dir = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK;		attr = endpoint[i].desc.bmAttributes;		psize = le16_to_cpu(endpoint[i].desc.wMaxPacketSize);		/* Is it a bulk endpoint ??? */		if(attr == USB_ENDPOINT_XFER_BULK) {			/* We need to find an IN and an OUT */			if(dir == USB_DIR_IN) {				/* This is our Rx endpoint */				self->bulk_in_ep = ep;			} else {				/* This is our Tx endpoint */				self->bulk_out_ep = ep;				self->bulk_out_mtu = psize;			}		} else {			if((attr == USB_ENDPOINT_XFER_INT) &&			   (dir == USB_DIR_IN)) {				/* This is our interrupt endpoint */				self->bulk_int_ep = ep;			} else {				IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);			}		}	}	IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",		__FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);	return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));}#ifdef IU_DUMP_CLASS_DESC/*------------------------------------------------------------------*//* * Function usb_irda_dump_class_desc(desc) * *    Prints out the contents of the IrDA class descriptor * */static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc){	/* Values are little endian */	printk("bLength=%x\n", desc->bLength);	printk("bDescriptorType=%x\n", desc->bDescriptorType);	printk("bcdSpecRevision=%x\n", le16_to_cpu(desc->bcdSpecRevision)); 	printk("bmDataSize=%x\n", desc->bmDataSize);	printk("bmWindowSize=%x\n", desc->bmWindowSize);	printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);	printk("wBaudRate=%x\n", le16_to_cpu(desc->wBaudRate));	printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);	printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);	printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);}#endif /* IU_DUMP_CLASS_DESC *//*------------------------------------------------------------------*//* * Function irda_usb_find_class_desc(intf) * *    Returns instance of IrDA class descriptor, or NULL if not found * * The class descriptor is some extra info that IrDA USB devices will * offer to us, describing their IrDA characteristics. We will use that in * irda_usb_init_qos() */static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf){	struct usb_device *dev = interface_to_usbdev (intf);	struct irda_class_desc *desc;	int ret;	desc = kmalloc(sizeof (*desc), GFP_KERNEL);	if (desc == NULL) 		return NULL;	memset(desc, 0, sizeof(*desc));	/* USB-IrDA class spec 1.0:	 *	6.1.3: Standard "Get Descriptor" Device Request is not	 *	       appropriate to retrieve class-specific descriptor	 *	6.2.5: Class Specific "Get Class Descriptor" Interface Request	 *	       is mandatory and returns the USB-IrDA class descriptor	 */	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),		IU_REQ_GET_CLASS_DESC,		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,		0, intf->altsetting->desc.bInterfaceNumber, desc,		sizeof(*desc), 500);		IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);	if (ret < sizeof(*desc)) {		IRDA_WARNING("usb-irda: class_descriptor read %s (%d)\n",			     (ret<0) ? "failed" : "too short", ret);	}	else if (desc->bDescriptorType != USB_DT_IRDA) {		IRDA_WARNING("usb-irda: bad class_descriptor type\n");	}	else {#ifdef IU_DUMP_CLASS_DESC		irda_usb_dump_class_desc(desc);#endif	/* IU_DUMP_CLASS_DESC */		return desc;	}	kfree(desc);	return NULL;}/*********************** USB DEVICE CALLBACKS ***********************//* * Main calls from the USB subsystem. * Mostly registering a new irda-usb device and removing it.... *//*------------------------------------------------------------------*//* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. * The USB layer protect us from reentrancy (via BKL), so we don't need * to spinlock in there... Jean II */static int irda_usb_probe(struct usb_interface *intf,			  const struct usb_device_id *id){	struct net_device *net;	struct usb_device *dev = interface_to_usbdev(intf);	struct irda_usb_cb *self = NULL;	struct usb_host_interface *interface;	struct irda_class_desc *irda_desc;	int ret = -ENOMEM;	int i;		/* Driver instance index / Rx URB index */	/* Note : the probe make sure to call us only for devices that	 * matches the list of dongle (top of the file). So, we	 * don't need to check if the dongle is really ours.	 * Jean II */	IRDA_MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",		     dev->devnum, le16_to_cpu(dev->descriptor.idVendor),		     le16_to_cpu(dev->descriptor.idProduct));	net = alloc_irdadev(sizeof(*self));	if (!net) 		goto err_out;	SET_MODULE_OWNER(net);	SET_NETDEV_DEV(net, &intf->dev);	self = net->priv;	self->netdev = net;	spin_lock_init(&self->lock);	init_timer(&self->rx_defer_timer);	self->capability = id->driver_info;	self->needspatch = ((self->capability & IUC_STIR421X) != 0);	/* Create all of the needed urbs */	if (self->capability & IUC_STIR421X) {		self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;		self->header_length = USB_IRDA_STIR421X_HEADER;	} else {		self->max_rx_urb = IU_MAX_RX_URBS;		self->header_length = USB_IRDA_HEADER;	}	self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *),				GFP_KERNEL);	for (i = 0; i < self->max_rx_urb; i++) {		self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);		if (!self->rx_urb[i]) {			goto err_out_1;		}	}	self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!self->tx_urb) {		goto err_out_1;	}	self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!self->speed_urb) {		goto err_out_2;	}	/* Is this really necessary? (no, except maybe for broken devices) */	if (usb_reset_configuration (dev) < 0) {		err("reset_configuration failed");		ret = -EIO;		goto err_out_3;	}	/* Is this really necessary? */	/* Note : some driver do hardcode the interface number, some others	 * specify an alternate, but very few driver do like this.	 * Jean II */	ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0);	IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->desc.bInterfaceNumber, ret);	switch (ret) {		case 0:			break;		case -EPIPE:		/* -EPIPE = -32 */			/* Martin Diehl says if we get a -EPIPE we should			 * be fine and we don't need to do a usb_clear_halt().			 * - Jean II */			IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __FUNCTION__);			break;		default:			IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);			ret = -EIO;			goto err_out_3;	}	/* Find our endpoints */	interface = intf->cur_altsetting;	if(!irda_usb_parse_endpoints(self, interface->endpoint,				     interface->desc.bNumEndpoints)) {		IRDA_ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);		ret = -EIO;		goto err_out_3;	}	self->usbdev = dev;	/* Find IrDA class descriptor */	irda_desc = irda_usb_find_class_desc(intf);	ret = -ENODEV;	if (irda_desc == NULL)		goto err_out_3;	if (self->needspatch) {		ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),				       0x02, 0x40, 0, 0, NULL, 0, 500);		if (ret < 0) {			IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret);			goto err_out_3;		} else {			mdelay(10);		}	}	self->irda_desc =  irda_desc;	self->present = 1;	self->netopen = 0;	self->usbintf = intf;	/* Allocate the buffer for speed changes */	/* Don't change this buffer size and allocation without doing	 * some heavy and complete testing. Don't ask why :-(	 * Jean II */	self->speed_buff = kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);	if (self->speed_buff == NULL) 		goto err_out_3;	memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);	self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length,				GFP_KERNEL);	if (self->tx_buff == NULL)		goto err_out_4;	ret = irda_usb_open(self);	if (ret) 		goto err_out_5;	IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);	usb_set_intfdata(intf, self);	if (self->needspatch) {		/* Now we fetch and upload the firmware patch */		ret = stir421x_patch_device(self);		self->needspatch = (ret < 0);		if (self->needspatch) {			IRDA_ERROR("STIR421X: Couldn't upload patch\n");			goto err_out_6;		}		/* replace IrDA class descriptor with what patched device is now reporting */		irda_desc = irda_usb_find_class_desc (self->usbintf);		if (irda_desc == NULL) {			ret = -ENODEV;			goto err_out_6;		}		if (self->irda_desc)			kfree (self->irda_desc);		self->irda_desc = irda_desc;		irda_usb_init_qos(self);	}	return 0;err_out_6:	unregister_netdev(self->netdev);err_out_5:	kfree(self->tx_buff);err_out_4:	kfree(self->speed_buff);err_out_3:	/* Free all urbs that we may have created */	usb_free_urb(self->speed_urb);err_out_2:	usb_free_urb(self->tx_urb);err_out_1:	for (i = 0; i < self->max_rx_urb; i++)		usb_free_urb(self->rx_urb[i]);	free_netdev(net);err_out:	return ret;}/*------------------------------------------------------------------*//* * The current irda-usb device is removed, the USB layer tell us * to shut it down... * One of the constraints is that when we exit this function, * we cannot use the usb_device no more. Gone. Destroyed. kfree(). * Most other subsystem allow you to destroy the instance at a time * when it's convenient to you, to postpone it to a later date, but * not the USB subsystem. * So, we must make bloody sure that everything gets deactivated. * Jean II */static void irda_usb_disconnect(struct usb_interface *intf){	unsigned long flags;	struct irda_usb_cb *self = usb_get_intfdata(intf);	int i;	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	usb_set_intfdata(intf, NULL);	if (!self)		return;	/* Make sure that the Tx path is not executing. - Jean II */	spin_lock_irqsave(&self->lock, flags);	/* Oups ! We are not there any more.	 * This will stop/desactivate the Tx path. - Jean II */	self->present = 0;	/* Kill defered Rx URB */	del_timer(&self->rx_defer_timer);	/* We need to have irq enabled to unlink the URBs. That's OK,	 * at this point the Tx path is gone - Jean II */	spin_unlock_irqrestore(&self->lock, flags);	/* Hum... Check if networking is still active (avoid races) */	if((self->netopen) || (self->irlap)) {		/* Accept no more transmissions */		/*netif_device_detach(self->netdev);*/		netif_stop_queue(self->netdev);		/* Stop all the receive URBs. Must be synchronous. */		for (i = 0; i < self->max_rx_urb; i++)			usb_kill_urb(self->rx_urb[i]);		/* Cancel Tx and speed URB.		 * Make sure it's synchronous to avoid races. */		usb_kill_urb(self->tx_urb);		usb_kill_urb(self->speed_urb);	}	/* Cleanup the device stuff */	irda_usb_close(self);	/* No longer attached to USB bus */	self->usbdev = NULL;	self->usbintf = NULL;	/* Clean up our urbs */	for (i = 0; i < self->max_rx_urb; i++)		usb_free_urb(self->rx_urb[i]);	kfree(self->rx_urb);	/* Clean up Tx and speed URB */	usb_free_urb(self->tx_urb);	usb_free_urb(self->speed_urb);	/* Free self and network device */	free_netdev(self->netdev);	IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __FUNCTION__);}/*------------------------------------------------------------------*//* * USB device callbacks */static struct usb_driver irda_driver = {	.name		= "irda-usb",	.probe		= irda_usb_probe,	.disconnect	= irda_usb_disconnect,	.id_table	= dongles,};/************************* MODULE CALLBACKS *************************//* * Deal with module insertion/removal * Mostly tell USB about our existence *//*------------------------------------------------------------------*//* * Module insertion */static int __init usb_irda_init(void){	int	ret;	ret = usb_register(&irda_driver);	if (ret < 0)		return ret;	IRDA_MESSAGE("USB IrDA support registered\n");	return 0;}module_init(usb_irda_init);/*------------------------------------------------------------------*//* * Module removal */static void __exit usb_irda_cleanup(void){	/* Deregister the driver and remove all pending instances */	usb_deregister(&irda_driver);}module_exit(usb_irda_cleanup);/*------------------------------------------------------------------*//* * Module parameters */module_param(qos_mtt_bits, int, 0);MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>");MODULE_DESCRIPTION("IrDA-USB Dongle Driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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