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

📄 irda-usb.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************** * * Filename:      irda-usb.c * Version:       0.9b * Description:   IrDA-USB Driver * Status:        Experimental  * Author:        Dag Brattli <dag@brattli.net> * *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> *      Copyright (C) 2001, Dag Brattli <dag@brattli.net> *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> *           *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************************************//* *			    IMPORTANT NOTE *			    -------------- * * As of kernel 2.4.10, this is the state of compliance and testing of * this driver (irda-usb) with regards to the USB low level drivers... * * This driver has been tested SUCCESSFULLY with the following drivers : *	o usb-uhci	(For Intel/Via USB controllers) *	o usb-ohci	(For other USB controllers) * * This driver has NOT been tested with the following drivers : *	o usb-ehci	(USB 2.0 controllers) * * This driver WON'T WORK with the following drivers : *	o uhci		(Alternate/JE driver for Intel/Via USB controllers) * Amongst the reasons : *	o uhci doesn't implement USB_ZERO_PACKET *	o uhci non-compliant use of urb->timeout * The final fix for USB_ZERO_PACKET in uhci is likely to be in 2.4.19 and * 2.5.8. With this fix, the driver will work properly. More on that later. * * Jean II *//*------------------------------------------------------------------*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/slab.h>#include <linux/rtnetlink.h>#include <linux/usb.h>#include <net/irda/irda.h>#include <net/irda/irlap.h>#include <net/irda/irda_device.h>#include <net/irda/wrapper.h>#include <net/irda/irda-usb.h>/*------------------------------------------------------------------*/static int qos_mtt_bits = 0;/* Master instance for each hardware found */#define NIRUSB 4		/* Max number of USB-IrDA dongles */static struct irda_usb_cb irda_instance[NIRUSB];/* These are the currently known IrDA USB dongles. Add new dongles here */static struct usb_device_id dongles[] = {	/* ACTiSYS Corp,  ACT-IR2000U FIR-USB Adapter */	{ USB_DEVICE(0x9c4, 0x011), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },	/* KC Technology Inc.,  KC-180 USB IrDA Device */	{ USB_DEVICE(0x50f, 0x180), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },	/* Extended Systems, Inc.,  XTNDAccess IrDA USB (ESI-9685) */	{ USB_DEVICE(0x8e9, 0x100), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS |	               USB_DEVICE_ID_MATCH_INT_SUBCLASS,	  bInterfaceClass: USB_CLASS_APP_SPEC,	  bInterfaceSubClass: USB_CLASS_IRDA,	  driver_info: IUC_DEFAULT, },	{ }, /* The end */};/* * Important note : * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not compliant * with the USB-IrDA specification (and actually very very different), and * there is no way this driver can support those devices, apart from * a complete rewrite... * Jean II */MODULE_DEVICE_TABLE(usb, dongles);/*------------------------------------------------------------------*/static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum);static void irda_usb_disconnect(struct usb_device *dev, void *ptr);static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);static int irda_usb_open(struct irda_usb_cb *self);static int irda_usb_close(struct irda_usb_cb *self);static void speed_bulk_callback(struct urb *urb);static void write_bulk_callback(struct urb *urb);static void irda_usb_receive(struct urb *urb);static int irda_usb_net_init(struct net_device *dev);static int irda_usb_net_open(struct net_device *dev);static int irda_usb_net_close(struct net_device *dev);static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static void irda_usb_net_timeout(struct net_device *dev);static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev);/************************ TRANSMIT ROUTINES ************************//* * Receive packets from the IrDA stack and send them on the USB pipe. * Handle speed change, timeout and lot's of uglyness... *//*------------------------------------------------------------------*//* * Function irda_usb_build_header(self, skb, header) * *   Builds USB-IrDA outbound header * * When we send an IrDA frame over an USB pipe, we add to it a 1 byte * header. This function create this header with the proper values. * * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 * that the setting of the link speed and xbof number in this outbound header * should be applied *AFTER* the frame has been sent. * Unfortunately, some devices are not compliant with that... It seems that * reading the spec is far too difficult... * Jean II */static void irda_usb_build_header(struct irda_usb_cb *self,				  __u8 *header,				  int	force){	/* Set the negotiated link speed */	if (self->new_speed != -1) {		/* Hum... Ugly hack :-(		 * Some device are not compliant with the spec and change		 * parameters *before* sending the frame. - Jean II		 */		if ((self->capability & IUC_SPEED_BUG) &&		    (!force) && (self->speed != -1)) {			/* No speed and xbofs change here			 * (we'll do it later in the write callback) */			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");			*header = 0;			return;		}		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);		self->speed = self->new_speed;		self->new_speed = -1;		switch (self->speed) {		case 2400:		        *header = SPEED_2400;			break;		default:		case 9600:			*header = SPEED_9600;			break;		case 19200:			*header = SPEED_19200;			break;		case 38400:			*header = SPEED_38400;			break;		case 57600:		        *header = SPEED_57600;			break;		case 115200:		        *header = SPEED_115200;			break;		case 576000:		        *header = SPEED_576000;			break;		case 1152000:		        *header = SPEED_1152000;			break;		case 4000000:		        *header = SPEED_4000000;			self->new_xbofs = 0;			break;		}	} else		/* No change */		*header = 0;		/* Set the negotiated additional XBOFS */	if (self->new_xbofs != -1) {		IRDA_DEBUG(2, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);		self->xbofs = self->new_xbofs;		self->new_xbofs = -1;		switch (self->xbofs) {		case 48:			*header |= 0x10;			break;		case 28:		case 24:	/* USB spec 1.0 says 24 */			*header |= 0x20;			break;		default:		case 12:			*header |= 0x30;			break;		case 5: /* Bug in IrLAP spec? (should be 6) */		case 6:			*header |= 0x40;			break;		case 3:			*header |= 0x50;			break;		case 2:			*header |= 0x60;			break;		case 1:			*header |= 0x70;			break;		case 0:			*header |= 0x80;			break;		}	}}/*------------------------------------------------------------------*//* * Send a command to change the speed of the dongle * Need to be called with spinlock on. */static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self){	__u8 *frame;	struct urb *urb;	int ret;	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",		   self->new_speed, self->new_xbofs);	/* Grab the speed URB */	urb = self->speed_urb;	if (urb->status != 0) {		WARNING(__FUNCTION__ "(), URB still in use!\n");		return;	}	/* Allocate the fake frame */	frame = self->speed_buff;	/* Set the new speed and xbofs in this fake frame */	irda_usb_build_header(self, frame, 1);	/* Submit the 0 length IrDA frame to trigger new speed settings */        FILL_BULK_URB(urb, self->usbdev,		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),                      frame, IRDA_USB_SPEED_MTU,                      speed_bulk_callback, self);	urb->transfer_buffer_length = USB_IRDA_HEADER;	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;	urb->timeout = MSECS_TO_JIFFIES(100);	/* Irq disabled -> GFP_ATOMIC */	if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {		WARNING(__FUNCTION__ "(), failed Speed URB\n");	}}/*------------------------------------------------------------------*//* * Note : this function will be called with both speed_urb and empty_urb... */static void speed_bulk_callback(struct urb *urb){	struct irda_usb_cb *self = urb->context;		IRDA_DEBUG(2, __FUNCTION__ "()\n");	/* We should always have a context */	if (self == NULL) {		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");		return;	}	/* 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.		 * 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;	/* If it was the speed URB, allow the stack to send more packets */	if(urb == self->speed_urb) {		netif_wake_queue(self->netdev);	}}/*------------------------------------------------------------------*//* * Send an IrDA frame to the USB dongle (for transmission) */static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev){	struct irda_usb_cb *self = netdev->priv;	struct urb *urb = self->tx_urb;	unsigned long flags;	s32 speed;	s16 xbofs;	int res, mtt;	netif_stop_queue(netdev);	/* Protect us from USB callbacks, net watchdog and else. */	spin_lock_irqsave(&self->lock, flags);	/* Check if the device is still there.	 * We need to check self->present under the spinlock because	 * of irda_usb_disconnect() is synchronous - Jean II */	if ((!self) || (!self->present)) {		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");		spin_unlock_irqrestore(&self->lock, flags);		return 1;	/* Failed */	}	/* Check if we need to change the number of xbofs */        xbofs = irda_get_next_xbofs(skb);        if ((xbofs != self->xbofs) && (xbofs != -1)) {		self->new_xbofs = xbofs;	}        /* Check if we need to change the speed */	speed = irda_get_next_speed(skb);	if ((speed != self->speed) && (speed != -1)) {		/* Set the desired speed */		self->new_speed = speed;		/* Check for empty frame */		if (!skb->len) {			/* IrLAP send us an empty frame to make us change the			 * speed. Changing speed with the USB adapter is in			 * fact sending an empty frame to the adapter, so we			 * could just let the present function do its job.			 * However, we would wait for min turn time,			 * do an extra memcpy and increment packet counters...			 * Jean II */			irda_usb_change_speed_xbofs(self);			netdev->trans_start = jiffies;			/* Will netif_wake_queue() in callback */			goto drop;		}	}	if (urb->status != 0) {		WARNING(__FUNCTION__ "(), URB still in use!\n");		goto drop;	}	/* Make sure there is room for IrDA-USB header. The actual	 * allocation will be done lower in skb_push().	 * Also, we don't use directly skb_cow(), because it require	 * headroom >= 16, which force unnecessary copies - Jean II */	if (skb_headroom(skb) < USB_IRDA_HEADER) {		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");		if (skb_cow(skb, USB_IRDA_HEADER)) {			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");			goto drop;		}	}	/* Change setting for next frame */	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);	/* FIXME: Make macro out of this one */	((struct irda_skb_cb *)skb->cb)->context = self;        FILL_BULK_URB(urb, self->usbdev, 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),                      skb->data, IRDA_USB_MAX_MTU,                      write_bulk_callback, skb);	urb->transfer_buffer_length = skb->len;	/* Note : unlink *must* be Asynchronous because of the code in 	 * irda_usb_net_timeout() -> call in irq - Jean II */	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;	/* This flag (USB_ZERO_PACKET) indicates that what we send is not	 * a continuous stream of data but separate packets.	 * In this case, the USB layer will insert an empty USB frame (TD)	 * after each of our packets that is exact multiple of the frame size.	 * This is how the dongle will detect the end of packet - Jean II */	urb->transfer_flags |= USB_ZERO_PACKET;	/* Timeout need to be shorter than NET watchdog timer */	urb->timeout = MSECS_TO_JIFFIES(200);

⌨️ 快捷键说明

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