lkml.org 
[lkml]   [2001]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
Subject[IrDA patch] ir249_irda-usb_reorg.diff
From
ir249_irda-usb_reorg.diff :
-------------------------
<Big patch, but not so many changes>
<Both mailing list will drop this patch because of its size>
<Apply to kernel-2.4.10-pre8 or later, include fixes from that kernel>
o [FEATURE] Reorganise the code logically, make it more maintainable
- At HP, we say that it has been "re-invented"
o [FEATURE] Lot's of comments, make it easier to read the code
- And also remove some misleading comments
o [CORRECT] Don't push same URB twice to USB stack (speed in KICK_TX)
o [FEATURE] Defered timeout handling. It's just safer.
o [FEATURE] Use the USB_ZERO_PACKET flag to avoid ugly KICK_TX code
- Safer, leaner and correct : it's a standard USB feature.
- Can revert back to old ugly way with a #define
- Please fix uhci.c and usb-ohci.c to handle USB_ZERO_PACKET
o [FEATURE] Reduce latency by not doing LAP turnaround in software
- May be re-enabled with a dongle option
o [FEATURE] Parse USB endpoint properly, get irq endpoint
o [FEATURE] Set USB transfer flags safely

diff -u -p linux/include/net/irda/irda-usb.d8.h linux/include/net/irda/irda-usb.h
--- linux/include/net/irda/irda-usb.d8.h Thu Sep 13 13:26:04 2001
+++ linux/include/net/irda/irda-usb.h Thu Sep 13 13:41:24 2001
@@ -1,13 +1,14 @@
/*****************************************************************************
*
* Filename: irda-usb.h
- * Version: 0.8
+ * Version: 0.9a
* Description: IrDA-USB Driver
* Status: Experimental
* Author: Dag Brattli <dag@brattli.net>
*
- * Copyright (C) 2001, Dag Brattli <dag@brattli.net>
- * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
+ * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
+ * Copyright (C) 2000, 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
@@ -35,13 +36,44 @@
#define IRDA_USB_MAX_MTU 2051
#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */

-/*
- * Maximum number of URB on the Rx and Tx path, a number larger than 1
- * is required for handling back-to-back (brickwalled) frames
- */
-#define IU_MAX_ACTIVE_RX_URBS 1
-#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1)
-#define IU_MAX_TX_URBS 1
+/* Maximum number of active URB on the Rx path
+ * This is the amount of buffers the we keep between the USB harware and the
+ * IrDA stack.
+ *
+ * Note : the network layer does also queue the packets between us and the
+ * IrDA stack, and is actually pretty fast and efficient in doing that.
+ * Therefore, we don't need to have a large number of URBs, and we can
+ * perfectly live happy with only one. We certainly don't need to keep the
+ * full IrTTP window around here...
+ * I repeat for those who have trouble to understand : 1 URB is plenty
+ * good enough to handle back-to-back (brickwalled) frames. I tried it,
+ * it works (it's the hardware that has trouble doing it).
+ *
+ * Having 2 URBs would allow the USB stack to process one URB while we take
+ * care of the other and then swap the URBs...
+ * On the other hand, increasing the number of URB will have penalities
+ * in term of latency and will interact with the link management in IrLAP...
+ * Jean II */
+#define IU_MAX_ACTIVE_RX_URBS 1 /* Don't touch !!! */
+
+/* When a Rx URB is passed back to us, we can't reuse it immediately,
+ * because it may still be referenced by the USB layer. Therefore we
+ * need to keep one extra URB in the Rx path.
+ * Jean II */
+#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1)
+
+/* Various ugly stuff to try to workaround generic problems */
+/* The USB layer should send empty frames at the end of packets multiple
+ * of the frame size. As it doesn't do it by default, we need to do it
+ * ourselves... See also following option. */
+#undef IU_BUG_KICK_TX
+/* Use the USB_ZERO_PACKET flag instead of sending empty frame (above)
+ * Work only with usb-uhci.o so far. Please fix uhic.c and usb-ohci.c */
+#define IU_USE_USB_ZERO_FLAG
+/* Send speed command in case of timeout, just for trying to get things sane */
+#define IU_BUG_KICK_TIMEOUT
+/* Show the USB class descriptor */
+#undef IU_DUMP_CLASS_DESC

/* Inbound header */
#define MEDIA_BUSY 0x80
@@ -56,15 +88,19 @@
#define SPEED_1152000 0x08
#define SPEED_4000000 0x09

-/* device_info flags in struct usb_device_id */
+/* Basic capabilities */
#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */
+/* Main bugs */
#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */
-#define IUC_SIR_ONLY 0x02 /* Device doesn't behave at FIR speeds */
-#define IUC_SMALL_PKT 0x04 /* Device doesn't behave with big Rx packets */
-#define IUC_NO_WINDOW 0x08 /* Device doesn't behave with big Rx window */
-#define IUC_MAX_WINDOW 0x10 /* Device underestimate the Rx window */
-#define IUC_MAX_XBOFS 0x20 /* Device need more xbofs than advertised */
+#define IUC_NO_WINDOW 0x02 /* Device doesn't behave with big Rx window */
+#define IUC_NO_TURN 0x04 /* Device doesn't do turnaround by itself */
+/* Not currently used */
+#define IUC_SIR_ONLY 0x08 /* Device doesn't behave at FIR speeds */
+#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
+#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
+#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */

+/* USB class definitions */
#define USB_IRDA_HEADER 0x01
#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
#define USB_DT_IRDA 0x21
@@ -89,23 +125,29 @@ struct irda_usb_cb {
int netopen; /* Device is active for network */
int present; /* Device is present on the bus */
__u32 capability; /* Capability of the hardware */
- __u8 bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
- __u16 bulk_out_mtu;
-
+ __u8 bulk_in_ep; /* Rx Endpoint assignments */
+ __u8 bulk_out_ep; /* Tx Endpoint assignments */
+ __u16 bulk_out_mtu; /* Max Tx packet size in bytes */
+ __u8 bulk_int_ep; /* Interrupt Endpoint assignments */
+
wait_queue_head_t wait_q; /* for timeouts */

- struct urb rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */
- struct urb *rx_idle_urb; /* Pointer to idle URB in Rx path */
+ struct urb rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */
+ struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */
struct urb tx_urb; /* URB used to send data frames */
struct urb speed_urb; /* URB used to send speed commands */
+#ifdef IU_BUG_KICK_TX
+ struct urb empty_urb; /* URB used to send empty commands */
+#endif IU_BUG_KICK_TX

struct net_device *netdev; /* Yes! we are some kind of netdev. */
struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos;
+ struct qos_info qos;
hashbin_t *tx_list; /* Queued transmit skb's */
+ char *speed_buff; /* Buffer for speed changes */

- struct timeval stamp;
+ struct timeval stamp;
struct timeval now;

spinlock_t lock; /* For serializing operations */
@@ -116,5 +158,4 @@ struct irda_usb_cb {
__s32 new_speed; /* speed we need to set */
__u32 flags; /* Interface flags */
};
-

diff -u -p linux/drivers/net/irda/irda-usb.d8.c linux/drivers/net/irda/irda-usb.c
--- linux/drivers/net/irda/irda-usb.d8.c Thu Sep 13 13:25:45 2001
+++ linux/drivers/net/irda/irda-usb.c Thu Sep 13 13:58:54 2001
@@ -1,14 +1,14 @@
/*****************************************************************************
*
* Filename: irda-usb.c
- * Version: 0.9
+ * Version: 0.9a
* 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>
- * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
*
* 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
@@ -46,23 +46,6 @@

static int qos_mtt_bits = 0;

-static void irda_usb_dump_class_desc(struct irda_class_desc *desc);
-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 irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
-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);
-
/* Master instance for each hardware found */
#define NIRUSB 4 /* Max number of USB-IrDA dongles */
static struct irda_usb_cb irda_instance[NIRUSB];
@@ -85,697 +68,649 @@ static struct usb_device_id dongles[] =

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(purb_t purb);
+static void write_bulk_callback(purb_t purb);
+static void irda_usb_receive(purb_t purb);
+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 ************************/
/*
- * 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.
- * Note : it might be worth protecting this function by a global
- * spinlock...
+ * Receive packets from the IrDA stack and send them on the USB pipe.
+ * Handle speed change, timeout and lot's of uglyness...
*/
-static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
- const struct usb_device_id *id)
-{
- struct irda_usb_cb *self = NULL;
- struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct irda_class_desc *irda_desc;
- int capability = id->driver_info;
- int ret;
- int ep;
- int i;
-
- IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
-
- MESSAGE("IRDA-USB found at address %d\n", dev->devnum);

- /* Try to cleanup all instance that have a pending disconnect
- * Instance will be in this state is the disconnect() occurs
- * before the net_close().
- * Jean II */
- for (i = 0; i < NIRUSB; i++) {
- struct irda_usb_cb *irda = &irda_instance[i];
- if ((irda->usbdev != NULL) &&
- (irda->present == 0) &&
- (irda->netopen == 0)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
- irda_usb_disconnect(irda->usbdev, (void *) irda);
+/*------------------------------------------------------------------*/
+/*
+ * 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;
}
- }

- /* Find an free instance to handle this new device... */
- self = NULL;
- for (i = 0; i < NIRUSB; i++) {
- if(irda_instance[i].usbdev == NULL) {
- self = &irda_instance[i];
+ 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;
}
- }
- if (self == NULL) {
- IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n",
- NIRUSB);
- return NULL;
- }
-
- /* Reset the instance */
- self->present = 0;
- self->netopen = 0;
-
- /* Is this really necessary? */
- if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
- err("set_configuration failed");
- return NULL;
- }
+ } else
+ /* No change */
+ *header = 0;

- /* Is this really necessary? */
- ret = usb_set_interface(dev, ifnum, 0);
- IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret);
- switch (ret) {
- case USB_ST_NOERROR: /* 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 USB_ST_STALL: /* -EPIPE = -32 */
- usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
- IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
+ case 28:
+ case 24: /* USB spec 1.0 says 24 */
+ *header |= 0x20;
break;
default:
- IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
- return NULL;
+ 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;
+ }
}
-
- /* Find our endpoints */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- endpoint = interface->endpoint;
- ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
- self->bulk_in_ep = ep;
- else {
- self->bulk_out_ep = ep;
- self->bulk_out_mtu = endpoint[0].wMaxPacketSize;
- }
-
- ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
- self->bulk_in_ep = ep;
- else {
- self->bulk_out_ep = ep;
- self->bulk_out_mtu = endpoint[1].wMaxPacketSize;
- }
-
- if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 ||
- endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK ||
- endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK)
- {
- ERROR(__FUNCTION__ "(), Bogus endpoints");
- return NULL;
- }
-
- /* Find IrDA class descriptor */
- irda_desc = irda_usb_find_class_desc(dev, ifnum);
- if (irda_desc == NULL)
- return NULL;
-
- self->irda_desc = irda_desc;
- self->present = 1;
- self->netopen = 0;
- self->capability = capability;
- self->usbdev = dev;
- ret = irda_usb_open(self);
- if (ret)
- return NULL;
-
- return self;
}

+/*------------------------------------------------------------------*/
/*
- * Function irda_usb_find_class_desc(dev, ifnum)
- *
- * Returns instance of IrDA class descriptor, or NULL if not found
- *
+ * Send a command to change the speed of the dongle
*/
-static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
{
- struct usb_interface_descriptor *interface;
- struct irda_class_desc *desc, *ptr;
+ unsigned long flags;
+ __u8 *frame;
+ purb_t purb;
int ret;
-
- desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
- if (desc == NULL)
- return NULL;
- memset(desc, 0, sizeof(struct irda_class_desc));
-
- ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
- IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret);
- if (ret) {
- WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret);
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
+ self->new_speed, self->new_xbofs);
+
+ /* Grab the speed URB */
+ purb = &self->speed_urb;
+ if (purb->status != USB_ST_NOERROR) {
+ WARNING(__FUNCTION__ "(), URB still in use!\n");
+ return;
}

- /* Check if we found it? */
- if (desc->bDescriptorType == USB_DT_IRDA)
- return desc;
+ spin_lock_irqsave(&self->lock, flags);

- IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n");
-
- /* Check if the class descriptor is interleaved with standard descriptors */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
- if (ret) {
- kfree(desc);
- return NULL;
+ /* 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(purb, self->usbdev,
+ usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+ frame, IRDA_USB_SPEED_MTU,
+ speed_bulk_callback, self);
+ purb->transfer_buffer_length = USB_IRDA_HEADER;
+ purb->transfer_flags = USB_QUEUE_BULK;
+ purb->timeout = MSECS_TO_JIFFIES(100);
+
+ if ((ret = usb_submit_urb(purb))) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n");
}
- *desc = *ptr;
-#if 0
- irda_usb_dump_class_desc(desc);
-#endif
- return desc;
+ spin_unlock_irqrestore(&self->lock, flags);
}

+#ifdef IU_BUG_KICK_TX
+/*------------------------------------------------------------------*/
/*
- * Function usb_irda_dump_class_desc(desc)
- *
- * Prints out the contents of the IrDA class descriptor
- *
+ * Send an empty URB to the dongle
+ * The goal there is to try to resynchronise with the dongle. An empty
+ * frame signify the end of a Tx frame. Jean II
*/
-static void irda_usb_dump_class_desc(struct irda_class_desc *desc)
+static inline void irda_usb_send_empty(struct irda_usb_cb *self)
{
- printk("bLength=%x\n", desc->bLength);
- printk("bDescriptorType=%x\n", desc->bDescriptorType);
- printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision);
- printk("bmDataSize=%x\n", desc->bmDataSize);
- printk("bmWindowSize=%x\n", desc->bmWindowSize);
- printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
- printk("wBaudRate=%x\n", desc->wBaudRate);
- printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
- printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
- printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
-}
-
-static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
-{
- struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
- int i;
+ purb_t purb;
+ int ret;

IRDA_DEBUG(0, __FUNCTION__ "()\n");

- /* Oups ! We are not there any more */
- self->present = 0;
-
- /* Hum... Check if networking is still active */
- if (self->netopen) {
- /* Accept no more transmissions */
- /*netif_device_detach(self->netdev);*/
- netif_stop_queue(self->netdev);
- /* Stop all the receive URBs */
- for (i = 0; i < IU_MAX_RX_URBS; i++)
- usb_unlink_urb(&(self->rx_urb[i]));
- /* Cancel Tx and speed URB */
- usb_unlink_urb(&(self->tx_urb));
- usb_unlink_urb(&(self->speed_urb));
-
- IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
- /* better not do anything just yet, usb_irda_cleanup()
- * will do whats needed */
+ /* Grab the empty URB */
+ purb = &self->empty_urb;
+ if (purb->status != USB_ST_NOERROR) {
+ WARNING(__FUNCTION__ "(), Empty URB still in use!\n");
return;
}

- /* Cleanup the device stuff */
- irda_usb_close(self);
- /* No longer attached to USB bus */
- self->usbdev = NULL;
- IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
-}
+ /* Submit the Empty URB */
+ FILL_BULK_URB(purb, self->usbdev,
+ usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+ self->speed_buff, IRDA_USB_SPEED_MTU,
+ speed_bulk_callback, self);
+ purb->transfer_buffer_length = 0;
+ purb->transfer_flags = USB_QUEUE_BULK;
+ purb->timeout = MSECS_TO_JIFFIES(100);

-static struct usb_driver irda_driver = {
- name: "irda-usb",
- probe: irda_usb_probe,
- disconnect: irda_usb_disconnect,
- id_table: dongles,
-};
+ if ((ret = usb_submit_urb(purb))) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), failed Empty URB\n");
+ }
+}
+#endif IU_BUG_KICK_TX

-static void irda_usb_init_qos(struct irda_usb_cb *self)
+/*------------------------------------------------------------------*/
+/*
+ * Note : this function will be called with both speed_urb and empty_urb...
+ */
+static void speed_bulk_callback(purb_t purb)
{
- struct irda_class_desc *desc;
-
- desc = self->irda_desc;
+ struct irda_usb_cb *self = purb->context;

- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- self->qos.baud_rate.bits = 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(2, __FUNCTION__ "()\n");

- IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", 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);
+ /* We should always have a context */
+ if (self == NULL) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
+ return;
+ }

- /* Don't always trust what the dongle tell us */
- if (self->capability & IUC_SIR_ONLY)
- self->qos.baud_rate.bits &= 0xff;
- 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;
+ /* Check for timeout and other USB nasties */
+ if(purb->status != USB_ST_NOERROR) {
+ /* I get a lot of -ECONNABORTED = -103 here - Jean II */
+ WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->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;
+ }

-#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);
+ /* urb is now available */
+ purb->status = USB_ST_NOERROR;

- self->flags |= IFF_SIR;
- if (self->qos.baud_rate.value > 115200)
- self->flags |= IFF_MIR;
- if (self->qos.baud_rate.value > 1152000)
- self->flags |= IFF_FIR;
- if (self->qos.baud_rate.value > 4000000)
- self->flags |= IFF_VFIR;
+ /* If it was the speed URB, allow the stack to send more packets */
+ if(purb == &self->speed_urb) {
+ netif_wake_queue(self->netdev);
+ }
}

-static int irda_usb_open(struct irda_usb_cb *self)
+/*------------------------------------------------------------------*/
+/*
+ * 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 net_device *netdev;
- int err;
+ struct irda_usb_cb *self = netdev->priv;
+ purb_t purb = &self->tx_urb;
+ unsigned long flags;
+ s32 speed;
+ s16 xbofs;
+ int res, mtt;

- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ /* Check if the device is still there */
+ if ((!self) || (!self->present)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+ return 1; /* Failed */
+ }

- spin_lock_init(&self->lock);
+ netif_stop_queue(netdev);

- irda_usb_init_qos(self);
-
- self->tx_list = hashbin_new(HB_GLOBAL);
+ /* 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;
+ }

- /* Create a network device for us */
- if (!(netdev = dev_alloc("irda%d", &err))) {
- ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
- return -1;
+ /* 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;
+ dev_kfree_skb(skb);
+ /* Will netif_wake_queue() in callback */
+ return 0;
+ }
}
- self->netdev = netdev;
- netdev->priv = (void *) self;

- /* Override the network functions we need to use */
- netdev->init = irda_usb_net_init;
- netdev->hard_start_xmit = irda_usb_hard_xmit;
- netdev->tx_timeout = irda_usb_net_timeout;
- netdev->watchdog_timeo = 110*HZ/1000; /* 110 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;
+ if (purb->status != USB_ST_NOERROR) {
+ WARNING(__FUNCTION__ "(), URB still in use!\n");
+ dev_kfree_skb(skb);
+ return 0;
+ }

- rtnl_lock();
- err = register_netdevice(netdev);
- rtnl_unlock();
- if (err) {
- ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
- return -1;
+ /* Make room for IrDA-USB header (note skb->len += USB_IRDA_HEADER) */
+ if (skb_cow(skb, USB_IRDA_HEADER)) {
+ dev_kfree_skb(skb);
+ return 0;
}
- MESSAGE("IrDA: Registered device %s\n", netdev->name);

- return 0;
-}
+ spin_lock_irqsave(&self->lock, flags);

-static int irda_usb_close(struct irda_usb_cb *self)
-{
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ /* Change setting for next frame */
+ irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);

- ASSERT(self != NULL, return -1;);
+ /* FIXME: Make macro out of this one */
+ ((struct irda_skb_cb *)skb->cb)->context = self;

- /* Remove netdevice */
- if (self->netdev) {
- rtnl_lock();
- unregister_netdevice(self->netdev);
- self->netdev = NULL;
- rtnl_unlock();
+ FILL_BULK_URB(purb, self->usbdev,
+ usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+ skb->data, IRDA_USB_MAX_MTU,
+ write_bulk_callback, skb);
+ purb->transfer_buffer_length = skb->len;
+ purb->transfer_flags = USB_QUEUE_BULK;
+#ifdef IU_USE_USB_ZERO_FLAG
+ /* This flag indicates that what we send is not a continuous stream
+ * of data but separate frames. In this case, the USB layer will
+ * insert empty packet to separate our frames.
+ * This flag was previously called USB_DISABLE_SPD - Jean II */
+ purb->transfer_flags |= USB_ZERO_PACKET;
+#endif IU_USE_USB_ZERO_FLAG
+ purb->timeout = MSECS_TO_JIFFIES(100);
+
+ /* Generate min turn time. FIXME: can we do better than this? */
+ /* Trying to a turnaround time at this level is trying to measure
+ * processor clock cycle with a 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;
+ get_fast_time(&self->now);
+ diff = self->now.tv_usec - self->stamp.tv_usec;
+ 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);
+ }
+ }
}
- hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
+
+ if ((res = usb_submit_urb(purb))) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n");
+ 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;
+
+#ifdef IU_BUG_KICK_TX
+ /* Kick Tx?
+ * If the packet is a multiple of 64, the USB layer
+ * should send an empty frame (a short packet) to signal
+ * the end of frame (that's part of the USB spec).
+ * If we enable USB_ZERO_PACKET, the USB layer will just do
+ * that (more efficiently) and this code is useless.
+ * Better keep this code until USB code clear up this mess...
+ *
+ * Note : we can't use the speed URB, because the frame
+ * might contain a speed change that may be deferred
+ * (so we have hard_xmit => tx_urb+empty_urb+speed_urb).
+ * Jean II */
+ if ((skb->len % self->bulk_out_mtu) == 0) {
+ IRDA_DEBUG(2, __FUNCTION__ "(), Kick Tx...\n");
+ irda_usb_send_empty(self);
+ }
+#endif IU_BUG_KICK_TX
+ }
+ spin_unlock_irqrestore(&self->lock, flags);

return 0;
}

+/*------------------------------------------------------------------*/
/*
- * Function irda_usb_build_header(self, skb, header)
- *
- * Builds USB-IrDA outbound header
- *
- * 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
+ * Note : this function will be called only for tx_urb...
*/
-static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header,
- int force)
+static void write_bulk_callback(purb_t purb)
{
- /* 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;
- }
+ struct sk_buff *skb = purb->context;
+ struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");

- IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
- self->speed = self->new_speed;
- self->new_speed = -1;
+ /* We should always have a context */
+ if (self == NULL) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
+ return;
+ }

- 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(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
- self->xbofs = self->new_xbofs;
- self->new_xbofs = -1;
+ /* Free up the skb */
+ dev_kfree_skb_any(skb);
+ purb->context = NULL;

- 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;
- }
+ /* Check for timeout and other USB nasties */
+ if(purb->status != USB_ST_NOERROR) {
+ /* I get a lot of -ECONNABORTED = -103 here - Jean II */
+ WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->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;
}
-}
-
-static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
-{
- struct sk_buff *skb;
- unsigned long flags;
- purb_t purb;
- int ret;

- IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
- self->new_speed, self->new_xbofs);
+ /* urb is now available */
+ purb->status = USB_ST_NOERROR;

- purb = &self->speed_urb;
- if (purb->status != USB_ST_NOERROR) {
- WARNING(__FUNCTION__ "(), URB still in use!\n");
+ /* If the network is closed, stop everything */
+ if ((!self->netopen) || (!self->present)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
return;
}
- spin_lock_irqsave(&self->lock, flags);
-
- /* Allocate the fake frame */
- skb = dev_alloc_skb(IRDA_USB_SPEED_MTU);
- if (!skb)
- return;
- ((struct irda_skb_cb *)skb->cb)->context = self;
-
- /* Set the new speed and xbofs in this fake frame */
- irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1);
-
- /* Submit the 0 length IrDA frame to trigger new speed settings */
- FILL_BULK_URB(purb, self->usbdev,
- usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- skb->data, IRDA_USB_MAX_MTU,
- write_bulk_callback, skb);
- purb->transfer_buffer_length = skb->len;
- purb->transfer_flags |= USB_QUEUE_BULK;
- purb->timeout = MSECS_TO_JIFFIES(100);

- if ((ret = usb_submit_urb(purb))) {
- IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n");
+ /* If we need to change the speed or xbofs, do it now */
+ if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n");
+ irda_usb_change_speed_xbofs(self);
+ } else {
+ /* Otherwise, allow the stack to send more packets */
+ netif_wake_queue(self->netdev);
}
- spin_unlock_irqrestore(&self->lock, flags);
}

-static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+/*------------------------------------------------------------------*/
+/*
+ * 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)
{
struct irda_usb_cb *self = netdev->priv;
- purb_t purb = &self->tx_urb;
- unsigned long flags;
- s32 speed;
- s16 xbofs;
- int mtt;
+ purb_t purb;
+ int done = 0; /* If we have made any progress */
+
+ IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");

- /* Check if the device is still there */
if ((!self) || (!self->present)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
- return 1; /* Failed */
+ WARNING(__FUNCTION__ "(), device not present!\n");
+ netif_stop_queue(netdev);
+ return;
}

- netif_stop_queue(netdev);
+#ifdef IU_BUG_KICK_TX
+ /* Check empty URB */
+ purb = &(self->empty_urb);
+ if (purb->status != USB_ST_NOERROR) {
+ WARNING("%s: Empty change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);

- /* 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;
+ switch (purb->status) {
+ case -ECONNABORTED: /* -103 */
+ case -ECONNRESET: /* -104 */
+ case -ENOENT: /* -2 */
+ purb->status = USB_ST_NOERROR;
+ done = 1;
+ break;
+ case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */
+ usb_unlink_urb(purb);
+ /* Note : above will *NOT* call netif_wake_queue()
+ * in completion handler - Jean II */
+ done = 1;
+ break;
+ default:
+ /* ??? */
+ break;
+ }
}
+#endif IU_BUG_KICK_TX

- /* 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 speed URB */
+ purb = &(self->speed_urb);
+ if (purb->status != USB_ST_NOERROR) {
+ WARNING("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);

- /* 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;
- dev_kfree_skb(skb);
- /* Will netif_wake_queue() in callback */
- return 0;
+ switch (purb->status) {
+ case -ECONNABORTED: /* -103 */
+ case -ECONNRESET: /* -104 */
+ case -ENOENT: /* -2 */
+ purb->status = USB_ST_NOERROR;
+ netif_wake_queue(self->netdev);
+ done = 1;
+ break;
+ case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */
+ usb_unlink_urb(purb);
+ /* Note : above will call netif_wake_queue()
+ * in completion handler - Jean II */
+ done = 1;
+ break;
+ default:
+ /* ??? */
+ break;
}
}

+ /* Check Tx URB */
+ purb = &(self->tx_urb);
if (purb->status != USB_ST_NOERROR) {
- WARNING(__FUNCTION__ "(), URB still in use!\n");
- dev_kfree_skb(skb);
- return 0;
- }
-
- /* Make room for IrDA-USB header */
- if (skb_cow(skb, USB_IRDA_HEADER)) {
- dev_kfree_skb(skb);
- return 0;
- }
+ struct sk_buff *skb = purb->context;

- spin_lock_irqsave(&self->lock, flags);
-
- /* Change setting for next frame */
- irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
+ WARNING("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);

- /* FIXME: Make macro out of this one */
- ((struct irda_skb_cb *)skb->cb)->context = self;
+ /* Increase error count */
+ self->stats.tx_errors++;

- FILL_BULK_URB(purb, self->usbdev,
- usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- skb->data, IRDA_USB_MAX_MTU,
- write_bulk_callback, skb);
- purb->transfer_buffer_length = skb->len;
- purb->transfer_flags |= USB_QUEUE_BULK;
- purb->timeout = MSECS_TO_JIFFIES(100);
-
- /* Generate min turn time */
- mtt = irda_get_mtt(skb);
- if (mtt) {
- int diff;
- get_fast_time(&self->now);
- diff = self->now.tv_usec - self->stamp.tv_usec;
- if (diff < 0)
- diff += 1000000;
+#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

- /* 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) {
- /*
- * FIXME: can we do better than this? Maybe call
- * a function which sends a frame to a non
- * existing device, or change the speed to the
- * current one a number of times just to burn
- * time a better way.
- */
- mdelay(mtt/1000);
- irda_usb_write_bulk(self, purb);
- goto out;
- } else
- udelay(mtt);
+ switch (purb->status) {
+ case -ECONNABORTED: /* -103 */
+ case -ECONNRESET: /* -104 */
+ case -ENOENT: /* -2 */
+ if(skb != NULL) {
+ dev_kfree_skb_any(skb);
+ purb->context = NULL;
+ }
+ purb->status = USB_ST_NOERROR;
+ netif_wake_queue(self->netdev);
+ done = 1;
+ break;
+ case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */
+ usb_unlink_urb(purb);
+ /* Note : above will call netif_wake_queue()
+ * in completion handler - Jean II */
+ done = 1;
+ break;
+ default:
+ /* ??? */
+ break;
}
- }
- irda_usb_write_bulk(self, purb);
-out:
- spin_unlock_irqrestore(&self->lock, flags);
-
- return 0;
-}
+ }

-static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb)
-{
- int len = purb->transfer_buffer_length;
- int res;
-
- if ((res = usb_submit_urb(purb))) {
- IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n");
- self->stats.tx_errors++;
- netif_start_queue(self->netdev);
+ /* Maybe we need a reset */
+ /* Note : Some drivers seem to use a usb_set_interface() when they
+ * need to reset the hardware. Hum...
+ */

- return;
- }
- self->stats.tx_packets++;
- self->stats.tx_bytes += len;
- self->netdev->trans_start = jiffies;
-
- /* Send empty frame if size if a multiple of the USB max packet size */
- ASSERT(self->bulk_out_mtu == 64, return;);
- if ((len % self->bulk_out_mtu) == 0) {
- /* Borrow speed urb */
- purb = &self->speed_urb;
- FILL_BULK_URB(purb, self->usbdev,
- usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- self, /* Anything not on the stack will do */
- IRDA_USB_MAX_MTU, NULL, NULL);
- purb->transfer_buffer_length = 0;
- purb->transfer_flags |= USB_QUEUE_BULK;
- res = usb_submit_urb(purb);
- }
+ /* if(done == 0) */
}

+/************************* RECEIVE ROUTINES *************************/
/*
- * Note : this function will be called with both tx_urb and speed_urb...
+ * Receive packets from the USB layer stack and pass them to the IrDA stack.
+ * Try to work around USB failures...
*/
-static void write_bulk_callback(purb_t purb)
-{
- struct sk_buff *skb = purb->context;
- struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
-
- /* We should always have a context */
- if (self == NULL) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
- return;
- }

- /* urb is now available */
- purb->status = USB_ST_NOERROR;
+/*------------------------------------------------------------------*/
+/*
+ * Submit a Rx URB to the USB layer to handle reception of a frame
+ *
+ * Important note :
+ * The function process_urb() in usb-uhci.c contains the following code :
+ * > urb->complete ((struct urb *) urb);
+ * > // Re-submit the URB if ring-linked
+ * > if (is_ring && (urb->status != -ENOENT) && !contains_killed) {
+ * > urb->dev=usb_dev;
+ * > uhci_submit_urb (urb);
+ * > }
+ * The way I see it is that if we submit more than one Rx URB at a
+ * time, the Rx URB can be automatically re-submitted after the
+ * completion handler is called.
+ * We make sure to disable this feature by setting urb->next to NULL
+ *
+ * My take is that it's a questionable feature, and quite difficult
+ * to control and to make work effectively.
+ * The outcome (re-submited or not) depend on various complex
+ * test ('is_ring' and 'contains_killed'), and the completion handler
+ * don't have this information, so basically the driver has no way
+ * to know if URB are resubmitted or not. Yuck !
+ * If everything is perfect, it's cool, but the problem is when
+ * an URB is killed (timeout, call to unlink_urb(), ...), things get
+ * messy...
+ * The other problem is that this scheme deal only with the URB
+ * and ignore everything about the associated buffer. So, it would
+ * resubmit URB even if the buffer is still in use or non-existent.
+ * On the other hand, submitting ourself in the completion callback
+ * is quite trivial and work well (this function).
+ * Moreover, this scheme doesn't allow to have an idle URB, which is
+ * necessary to overcome some URB failures.
+ *
+ * Jean II
+ */
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+{
+ struct irda_skb_cb *cb;
+ int ret;

- dev_kfree_skb_any(skb);
- purb->context = NULL;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");

- /* Check for timeout and other USB nasties */
- if (purb->status != USB_ST_NOERROR) {
- /* I get a lot of -ECONNABORTED = -103 here - Jean II */
- WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n",
- purb->status, purb->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 */
- purb->status = USB_ST_NOERROR;
-
- /* If the network is closed, stop everything */
- if ((!self->netopen) || (!self->present)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
- return;
- }
-
- /* If we need to change the speed or xbofs, do it now */
- if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n");
- irda_usb_change_speed_xbofs(self);
- } else {
- /* Otherwise, allow the stack to send more packets */
- netif_wake_queue(self->netdev);
- }
-}
-
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
-{
- struct irda_skb_cb *cb;
- int ret;
-
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
- /* Check that we have an urb */
- if (!purb) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n");
- return;
+ /* Check that we have an urb */
+ if (!purb) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n");
+ return;
}

/* Allocate new skb if it has not been recycled */
@@ -804,9 +739,9 @@ static void irda_usb_submit(struct irda_
usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep),
skb->data, skb->truesize,
irda_usb_receive, skb);
- purb->transfer_flags |= USB_QUEUE_BULK;
+ purb->transfer_flags = USB_QUEUE_BULK;
purb->status = USB_ST_NOERROR;
- purb->next = NULL; /* Make sure we don't auto resubmit */
+ purb->next = NULL; /* Don't auto resubmit URBs */

ret = usb_submit_urb(purb);
if (ret) {
@@ -816,6 +751,7 @@ static void irda_usb_submit(struct irda_
}
}

+/*------------------------------------------------------------------*/
/*
* Function irda_usb_receive(purb)
*
@@ -829,6 +765,8 @@ static void irda_usb_receive(purb_t purb
struct irda_skb_cb *cb;
struct sk_buff *new;

+ IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+
/* Find ourselves */
cb = (struct irda_skb_cb *) skb->cb;
ASSERT(cb != NULL, return;);
@@ -843,25 +781,25 @@ static void irda_usb_receive(purb_t purb
}

/* Check the status */
- if (purb->status != USB_ST_NOERROR) {
+ if(purb->status != USB_ST_NOERROR) {
switch (purb->status) {
case USB_ST_CRC: /* -EILSEQ */
self->stats.rx_errors++;
self->stats.rx_crc_errors++;
break;
- case -ECONNRESET:
- WARNING(__FUNCTION__ "(), Connection Reset !!!\n");
+ case -ECONNRESET: /* -104 */
+ WARNING(__FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
/* 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 */
break;
default:
- WARNING(__FUNCTION__ "(), RX status %d\n", purb->status);
+ WARNING(__FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
break;
}
goto done;
}
-
+
/* Check for empty frames */
if (purb->actual_length <= USB_IRDA_HEADER) {
WARNING(__FUNCTION__ "(), empty frame!\n");
@@ -892,7 +830,7 @@ static void irda_usb_receive(purb_t purb

/* Copy packet, so we can recycle the original */
memcpy(skb_put(new, skb->len), skb->data, skb->len);
- /* We will cleanup the skb in irda_usb_submit */
+ /* We will cleanup the skb in irda_usb_submit() */
} else {
/* Deliver the original skb */
new = skb;
@@ -907,17 +845,65 @@ static void irda_usb_receive(purb_t purb
new->mac.raw = new->data;
new->protocol = htons(ETH_P_IRDA);
netif_rx(new);
+
done:
- /* Recycle Rx URB (and possible the skb as well) */
- irda_usb_submit(self, skb, self->rx_idle_urb);
+ /* Note : at this point, the URB we've just received (purb)
+ * 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 */

- /* Recycle Rx URB : Now, the idle URB is the present one */
- self->rx_idle_urb = purb;
+ /* 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 */
+ self->idle_rx_urb = purb;
purb->context = NULL;
- /* Prevent the USB layer playing games with our URBs */
- purb->status = -ENOENT;
}

+/*------------------------------------------------------------------*/
+/*
+ * 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...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Callback when a new IrDA device is created.
+ */
static int irda_usb_net_init(struct net_device *dev)
{
IRDA_DEBUG(0, __FUNCTION__ "()\n");
@@ -930,6 +916,7 @@ static int irda_usb_net_init(struct net_
return 0;
}

+/*------------------------------------------------------------------*/
/*
* Function irda_usb_net_open (dev)
*
@@ -940,6 +927,7 @@ static int irda_usb_net_init(struct net_
static int irda_usb_net_open(struct net_device *netdev)
{
struct irda_usb_cb *self;
+ char hwname[16];
int i;

IRDA_DEBUG(0, __FUNCTION__ "()\n");
@@ -970,174 +958,597 @@ static int irda_usb_net_open(struct net_
* 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);
ASSERT(self->irlap != NULL, return -1;);

/* Allow IrLAP to send data to us */
netif_start_queue(netdev);

- /* 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++)
- irda_usb_submit(self, NULL, &(self->rx_urb[i]));
- /* Note : we submit all the Rx URB except for one - Jean II */
- self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
- self->rx_idle_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++)
+ irda_usb_submit(self, NULL, &(self->rx_urb[i]));
+ /* Note : we submit all the Rx URB except for one - Jean II */
+ self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
+ self->idle_rx_urb->context = NULL;
+
+ /* Ready to play !!! */
+ MOD_INC_USE_COUNT;
+ 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(0, __FUNCTION__ "()\n");
+
+ 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++) {
+ purb_t purb = &(self->rx_urb[i]);
+ struct sk_buff *skb = (struct sk_buff *) purb->context;
+ /* Cancel the receive command */
+ usb_unlink_urb(purb);
+ /* The skb is ours, free it */
+ if(skb) {
+ dev_kfree_skb(skb);
+ purb->context = NULL;
+ }
+ }
+ /* Cancel Tx and speed URB */
+ usb_unlink_urb(&(self->tx_urb));
+ usb_unlink_urb(&(self->speed_urb));
+
+ /* Stop and remove instance of IrLAP */
+ if (self->irlap)
+ irlap_close(self->irlap);
+ self->irlap = NULL;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ 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, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+
+ /* Check if the device is still there */
+ if(!self->present)
+ return -EFAULT;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ /* Set the desired speed */
+ self->new_speed = irq->ifr_baudrate;
+ irda_usb_change_speed_xbofs(self);
+ /* Note : will spinlock in above function */
+ break;
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ 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, __FUNCTION__ "()\n");
+
+ desc = self->irda_desc;
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&self->qos);
+
+ self->qos.baud_rate.bits = 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, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", 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 &= 0xff;
+ 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);
+
+ self->flags |= IFF_SIR;
+ if (self->qos.baud_rate.value > 115200)
+ self->flags |= IFF_MIR;
+ if (self->qos.baud_rate.value > 1152000)
+ self->flags |= IFF_FIR;
+ if (self->qos.baud_rate.value > 4000000)
+ self->flags |= IFF_VFIR;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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;
+ int err;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ spin_lock_init(&self->lock);
+
+ irda_usb_init_qos(self);
+
+ /* Initialise list of skb beeing curently transmitted */
+ self->tx_list = hashbin_new(HB_GLOBAL);
+
+ /* 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 = (char *) kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
+ if (self->speed_buff == NULL)
+ return -1;
+ memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
+
+ /* Create a network device for us */
+ if (!(netdev = dev_alloc("irda%d", &err))) {
+ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+ return -1;
+ }
+ self->netdev = netdev;
+ netdev->priv = (void *) self;
+
+ /* Override the network functions we need to use */
+ netdev->init = irda_usb_net_init;
+ netdev->hard_start_xmit = irda_usb_hard_xmit;
+ netdev->tx_timeout = irda_usb_net_timeout;
+ netdev->watchdog_timeo = 110*HZ/1000; /* 110 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;
+
+ rtnl_lock();
+ err = register_netdevice(netdev);
+ rtnl_unlock();
+ if (err) {
+ ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+ return -1;
+ }
+ MESSAGE("IrDA: Registered device %s\n", netdev->name);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Cleanup the network side of the irda-usb instance
+ * Called when a USB instance is removed in irda_usb_disconnect()
+ */
+static inline int irda_usb_close(struct irda_usb_cb *self)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return -1;);
+
+ /* Remove netdevice */
+ if (self->netdev) {
+ rtnl_lock();
+ unregister_netdevice(self->netdev);
+ self->netdev = NULL;
+ rtnl_unlock();
+ }
+ /* Delete all pending skbs */
+ hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
+ /* Remove the speed buffer */
+ if (self->speed_buff != NULL) {
+ kfree(self->speed_buff);
+ self->speed_buff = NULL;
+ }
+
+ return 0;
+}
+
+/********************** 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_endpoint_descriptor *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].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ dir = endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+ attr = endpoint[i].bmAttributes;
+ psize = endpoint[i].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 {
+ ERROR(__FUNCTION__ "(), Unrecognised endpoint %02X.\n", ep);
+ }
+ }
+ }
+
+ IRDA_DEBUG(0, __FUNCTION__ "(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
+ /* Should be 8, 16, 32 or 64 bytes */
+ ASSERT(self->bulk_out_mtu == 64, ;);
+
+ 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)
+{
+ printk("bLength=%x\n", desc->bLength);
+ printk("bDescriptorType=%x\n", desc->bDescriptorType);
+ printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision);
+ printk("bmDataSize=%x\n", desc->bmDataSize);
+ printk("bmWindowSize=%x\n", desc->bmWindowSize);
+ printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+ printk("wBaudRate=%x\n", 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(dev, ifnum)
+ *
+ * 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_device *dev, unsigned int ifnum)
+{
+ struct usb_interface_descriptor *interface;
+ struct irda_class_desc *desc, *ptr;
+ int ret;
+
+ desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
+ if (desc == NULL)
+ return NULL;
+ memset(desc, 0, sizeof(struct irda_class_desc));
+
+ ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
+ IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret);
+ if (ret) {
+ WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret);
+ }
+
+ /* Check if we found it? */
+ if (desc->bDescriptorType == USB_DT_IRDA)
+ return desc;

- /* Ready to play !!! */
- MOD_INC_USE_COUNT;
- return 0;
+ IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n");
+
+ /* Check if the class descriptor is interleaved with standard descriptors */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
+ if (ret) {
+ kfree(desc);
+ return NULL;
+ }
+ *desc = *ptr;
+#ifdef IU_DUMP_CLASS_DESC
+ irda_usb_dump_class_desc(desc);
+#endif IU_DUMP_CLASS_DESC
+ return desc;
}

+/*********************** USB DEVICE CALLBACKS ***********************/
/*
- * Function irda_usb_net_close (self)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
+ * Main calls from the USB subsystem.
+ * Mostly registering a new irda-usb device and removing it....
*/
-static int irda_usb_net_close(struct net_device *netdev)
+
+/*------------------------------------------------------------------*/
+/*
+ * 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.
+ * Note : it might be worth protecting this function by a global
+ * spinlock... Or not, because maybe USB already deal with that...
+ */
+static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
- struct irda_usb_cb *self;
+ struct irda_usb_cb *self = NULL;
+ struct usb_interface_descriptor *interface;
+ struct irda_class_desc *irda_desc;
+ int ret;
int i;

- IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
- 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;
+ /* 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 */

- /* Stop network Tx queue */
- netif_stop_queue(netdev);
+ IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+ MESSAGE("IRDA-USB found at address %d\n", dev->devnum);

- /* Deallocate all the Rx path buffers (URBs and skb) */
- for (i = 0; i < IU_MAX_RX_URBS; i++) {
- purb_t purb = &(self->rx_urb[i]);
- struct sk_buff *skb = (struct sk_buff *) purb->context;
- /* Cancel the receive command */
- usb_unlink_urb(purb);
- /* The skb is ours, free it */
- if (skb) {
- dev_kfree_skb(skb);
- purb->context = NULL;
+ /* Try to cleanup all instance that have a pending disconnect
+ * Instance will be in this state is the disconnect() occurs
+ * before the net_close().
+ * Jean II */
+ for (i = 0; i < NIRUSB; i++) {
+ struct irda_usb_cb *irda = &irda_instance[i];
+ if((irda->usbdev != NULL) &&
+ (irda->present == 0) &&
+ (irda->netopen == 0)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
+ irda_usb_disconnect(irda->usbdev, (void *) irda);
}
}
- /* Cancel Tx and speed URB */
- usb_unlink_urb(&self->tx_urb);
- usb_unlink_urb(&self->speed_urb);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- MOD_DEC_USE_COUNT;
-
- return 0;
-}

-static void irda_usb_net_timeout(struct net_device *netdev)
-{
- struct irda_usb_cb *self = netdev->priv;
- int done = 0; /* If we have made any progress */
- purb_t purb;
+ /* Find an free instance to handle this new device... */
+ self = NULL;
+ for (i = 0; i < NIRUSB; i++) {
+ if(irda_instance[i].usbdev == NULL) {
+ self = &irda_instance[i];
+ break;
+ }
+ }
+ if(self == NULL) {
+ IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n",
+ NIRUSB);
+ return NULL;
+ }

- IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
+ /* Reset the instance */
+ self->present = 0;
+ self->netopen = 0;

- if (!self || !self->present) {
- WARNING(__FUNCTION__ "(), device not present!\n");
- netif_stop_queue(netdev);
- return;
+ /* Is this really necessary? */
+ if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+ err("set_configuration failed");
+ return NULL;
}
- WARNING("%s: Tx timed out\n", netdev->name);

- /* Check Tx URB */
- purb = &self->tx_urb;
- switch (purb->status) {
- case -ECONNABORTED: /* Can't find proper USB_ST_* code */
- purb->status = USB_ST_NOERROR;
- netif_wake_queue(self->netdev);
- done = 1;
+ /* 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, ifnum, 0);
+ IRDA_DEBUG(0, "usb-irda: set interface %d result %d\n", ifnum, ret);
+ switch (ret) {
+ case USB_ST_NOERROR: /* 0 */
break;
- case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */
- usb_unlink_urb(purb);
- done = 1;
+ case USB_ST_STALL: /* -EPIPE = -32 */
+ usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+ IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
break;
default:
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
+ return NULL;
break;
}
- /* Check speed URB */
- purb = &self->speed_urb;
- switch (purb->status) {
- case -ECONNABORTED: /* Can't find proper USB_ST_* code */
- purb->status = USB_ST_NOERROR;
- netif_wake_queue(self->netdev);
- done = 1;
- break;
- case USB_ST_URB_PENDING: /* -EINPROGRESS */
- usb_unlink_urb(purb);
- done = 1;
- break;
- default:
- break;
+
+ /* Find our endpoints */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ if(!irda_usb_parse_endpoints(self, interface->endpoint,
+ interface->bNumEndpoints)) {
+ ERROR(__FUNCTION__ "(), Bogus endpoints...\n");
+ return NULL;
}
- /* Maybe we need a reset */
- /* if(done == 0) */
-}

-static int irda_usb_is_receiving(struct irda_usb_cb *self)
-{
- return 0; /* For now */
+ /* Find IrDA class descriptor */
+ irda_desc = irda_usb_find_class_desc(dev, ifnum);
+ if (irda_desc == NULL)
+ return NULL;
+
+ self->irda_desc = irda_desc;
+ self->present = 1;
+ self->netopen = 0;
+ self->capability = id->driver_info;
+ self->usbdev = dev;
+ ret = irda_usb_open(self);
+ if (ret)
+ return NULL;
+
+ return self;
}

-static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/*------------------------------------------------------------------*/
+/*
+ * The current irda-usb device is removed, the USB layer tell us
+ * to shut it down...
+ */
+static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct irda_usb_cb *self;
- int ret = 0;
+ struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
+ int i;

- ASSERT(dev != NULL, return -1;);
- self = dev->priv;
- ASSERT(self != NULL, return -1;);
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");

- IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+ /* Oups ! We are not there any more */
+ self->present = 0;

- /* Check if the device is still there */
- if (!self->present)
- return -EFAULT;
+ /* Hum... Check if networking is still active */
+ if (self->netopen) {
+ /* Accept no more transmissions */
+ /*netif_device_detach(self->netdev);*/
+ netif_stop_queue(self->netdev);
+ /* Stop all the receive URBs */
+ for (i = 0; i < IU_MAX_RX_URBS; i++)
+ usb_unlink_urb(&(self->rx_urb[i]));
+ /* Cancel Tx and speed URB */
+ usb_unlink_urb(&(self->tx_urb));
+ usb_unlink_urb(&(self->speed_urb));

- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- /* Set the desired speed */
- self->new_speed = irq->ifr_baudrate;
- irda_usb_change_speed_xbofs(self);
- /* Note : will spinlock in above function */
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- 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;
+ IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
+ /* better not do anything just yet, usb_irda_cleanup()
+ * will do whats needed */
+ return;
}
- return ret;
-}

-static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
-{
- struct irda_usb_cb *self = dev->priv;
- return &self->stats;
+ /* Cleanup the device stuff */
+ irda_usb_close(self);
+ /* No longer attached to USB bus */
+ self->usbdev = NULL;
+ IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
}

+/*------------------------------------------------------------------*/
+/*
+ * 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
+ */
int __init usb_irda_init(void)
{
if (usb_register(&irda_driver) < 0)
@@ -1148,10 +1559,14 @@ int __init usb_irda_init(void)
}
module_init(usb_irda_init);

+/*------------------------------------------------------------------*/
+/*
+ * Module removal
+ */
void __exit usb_irda_cleanup(void)
{
struct irda_usb_cb *irda = NULL;
- int i;
+ int i;

/* Find zombie instances and kill them... */
for (i = 0; i < NIRUSB; i++) {
@@ -1162,15 +1577,17 @@ void __exit usb_irda_cleanup(void)
irda_usb_disconnect(irda->usbdev, (void *) irda);
}
}
+
/* Deregister the driver and remove all pending instances */
usb_deregister(&irda_driver);
}
module_exit(usb_irda_cleanup);

+/*------------------------------------------------------------------*/
+/*
+ * Module parameters
+ */
MODULE_PARM(qos_mtt_bits, "i");
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver");
-
-
-
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 13:03    [W:0.101 / U:1.776 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site