patch-2.4.10 linux/drivers/net/irda/irda-usb.c
Next file: linux/drivers/net/irda/irport.c
Previous file: linux/drivers/net/irda/ali-ircc.c
Back to the patch index
Back to the overall index
- Lines: 2210
- Date:
Mon Sep 17 22:52:35 2001
- Orig file:
v2.4.9/linux/drivers/net/irda/irda-usb.c
- Orig date:
Sun Aug 12 13:27:59 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
@@ -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
@@ -44,26 +44,8 @@
#include <net/irda/irda-usb.h>
-static u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
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];
@@ -76,7 +58,8 @@
{ 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,
+ { 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, },
@@ -85,697 +68,649 @@
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 @@
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 @@
}
}
+/*------------------------------------------------------------------*/
/*
* Function irda_usb_receive(purb)
*
@@ -829,6 +765,8 @@
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 @@
}
/* 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 @@
/* 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 @@
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 @@
return 0;
}
+/*------------------------------------------------------------------*/
/*
* Function irda_usb_net_open (dev)
*
@@ -940,6 +927,7 @@
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 @@
* Open new IrLAP layer instance to take care of us...
* Note : will send immediately a speed change...
*/
- self->irlap = irlap_open(netdev, &self->qos);
+ sprintf(hwname, "usb#%d", self->usbdev->devnum);
+ self->irlap = irlap_open(netdev, &self->qos, hwname);
ASSERT(self->irlap != NULL, return -1;);
/* Allow IrLAP to send data to us */
netif_start_queue(netdev);
- /* 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 @@
}
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 @@
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");
-
-
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)