/*------------------------------------------------------------------*/
#include <linux/module.h>
-
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
/*
* Important note :
- * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not compliant
- * with the USB-IrDA specification (and actually very very different), and
- * there is no way this driver can support those devices, apart from
- * a complete rewrite...
+ * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not designed
+ * using the "USB-IrDA specification" (yes, there exist such a thing), and
+ * therefore not supported by this driver (don't add them above).
+ * There is a Linux driver, stir4200, that support those USB devices.
* Jean II
*/
static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs);
static void write_bulk_callback(struct urb *urb, struct pt_regs *regs);
static void irda_usb_receive(struct urb *urb, struct pt_regs *regs);
+static void irda_usb_rx_defer_expired(unsigned long data);
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);
/* Grab the speed URB */
urb = self->speed_urb;
if (urb->status != 0) {
- WARNING("%s(), URB still in use!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__);
return;
}
frame, IRDA_USB_SPEED_MTU,
speed_bulk_callback, self);
urb->transfer_buffer_length = USB_IRDA_HEADER;
- urb->transfer_flags = URB_ASYNC_UNLINK;
+ urb->transfer_flags = 0;
/* Irq disabled -> GFP_ATOMIC */
if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
- WARNING("%s(), failed Speed URB\n", __FUNCTION__);
+ IRDA_WARNING("%s(), failed Speed URB\n", __FUNCTION__);
}
}
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* We should always have a context */
- ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
/* We should always be called for the speed URB */
- ASSERT(urb == self->speed_urb, return;);
+ IRDA_ASSERT(urb == self->speed_urb, return;);
/* Check for timeout and other USB nasties */
if (urb->status != 0) {
}
if (urb->status != 0) {
- WARNING("%s(), URB still in use!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__);
goto drop;
}
if (skb_headroom(skb) < USB_IRDA_HEADER) {
IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
if (skb_cow(skb, USB_IRDA_HEADER)) {
- WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
goto drop;
}
}
skb->data, IRDA_SKB_MAX_MTU,
write_bulk_callback, skb);
urb->transfer_buffer_length = skb->len;
- /* Note : unlink *must* be Asynchronous because of the code in
- * irda_usb_net_timeout() -> call in irq - Jean II */
- urb->transfer_flags = URB_ASYNC_UNLINK;
/* This flag (URB_ZERO_PACKET) indicates that what we send is not
* a continuous stream of data but separate packets.
* In this case, the USB layer will insert an empty USB frame (TD)
* after each of our packets that is exact multiple of the frame size.
* This is how the dongle will detect the end of packet - Jean II */
- urb->transfer_flags |= URB_ZERO_PACKET;
+ urb->transfer_flags = URB_ZERO_PACKET;
/* Generate min turn time. FIXME: can we do better than this? */
/* Trying to a turnaround time at this level is trying to measure
/* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */
if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {
- WARNING("%s(), failed Tx URB\n", __FUNCTION__);
+ IRDA_WARNING("%s(), failed Tx URB\n", __FUNCTION__);
self->stats.tx_errors++;
/* Let USB recover : We will catch that in the watchdog */
/*netif_start_queue(netdev);*/
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* We should always have a context */
- ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
/* We should always be called for the speed URB */
- ASSERT(urb == self->tx_urb, return;);
+ IRDA_ASSERT(urb == self->tx_urb, return;);
/* Free up the skb */
dev_kfree_skb_any(skb);
int done = 0; /* If we have made any progress */
IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__);
- ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
/* Protect us from USB callbacks, net Tx and else. */
spin_lock_irqsave(&self->lock, flags);
/* self->present *MUST* be read under spinlock */
if (!self->present) {
- WARNING("%s(), device not present!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);
netif_stop_queue(netdev);
spin_unlock_irqrestore(&self->lock, flags);
return;
* in completion handler, because urb->status will
* be -ENOENT. We will fix that at the next watchdog,
* leaving more time to USB to recover...
- * Also, we are in interrupt, so we need to have
- * URB_ASYNC_UNLINK to work properly...
* Jean II */
done = 1;
break;
* on the interrupt pipe and hang the Rx URB only when an interrupt is
* received.
* Jean II
+ *
+ * Note : don't read the above as what we are currently doing, but as
+ * something we could do with KC dongle. Also don't forget that the
+ * interrupt pipe is not part of the original standard, so this would
+ * need to be optional...
+ * Jean II
*/
/*------------------------------------------------------------------*/
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* This should never happen */
- ASSERT(skb != NULL, return;);
- ASSERT(urb != NULL, return;);
+ IRDA_ASSERT(skb != NULL, return;);
+ IRDA_ASSERT(urb != NULL, return;);
/* Save ourselves in the skb */
cb = (struct irda_skb_cb *) skb->cb;
/* Reinitialize URB */
usb_fill_bulk_urb(urb, self->usbdev,
usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep),
- skb->data, skb->truesize,
+ skb->data, IRDA_SKB_MAX_MTU,
irda_usb_receive, skb);
- /* Note : unlink *must* be synchronous because of the code in
- * irda_usb_net_close() -> free the skb - Jean II */
urb->status = 0;
/* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */
if (ret) {
/* If this ever happen, we are in deep s***.
* Basically, the Rx path will stop... */
- WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret);
+ IRDA_WARNING("%s(), Failed to submit Rx URB %d\n",
+ __FUNCTION__, ret);
}
}
struct irda_skb_cb *cb;
struct sk_buff *newskb;
struct sk_buff *dataskb;
- int docopy;
+ struct urb *next_urb;
+ unsigned int len, docopy;
IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
/* Find ourselves */
cb = (struct irda_skb_cb *) skb->cb;
- ASSERT(cb != NULL, return;);
+ IRDA_ASSERT(cb != NULL, return;);
self = (struct irda_usb_cb *) cb->context;
- ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
/* If the network is closed or the device gone, stop everything */
if ((!self->netopen) || (!self->present)) {
if (urb->status != 0) {
switch (urb->status) {
case -EILSEQ:
- self->stats.rx_errors++;
self->stats.rx_crc_errors++;
- break;
+ /* Also precursor to a hot-unplug on UHCI. */
+ /* Fallthrough... */
case -ECONNRESET: /* -104 */
- IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, urb->transfer_flags);
+ /* Random error, if I remember correctly */
/* 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;
+ case -ESHUTDOWN: /* -108 */
+ /* That's usually a hot-unplug. Submit will fail... */
+ case -ETIMEDOUT: /* -110 */
+ /* Usually precursor to a hot-unplug on OHCI. */
default:
- IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags);
+ self->stats.rx_errors++;
+ IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags);
break;
}
- goto done;
+ /* If we received an error, we don't want to resubmit the
+ * Rx URB straight away but to give the USB layer a little
+ * bit of breathing room.
+ * We are in the USB thread context, therefore there is a
+ * danger of recursion (new URB we submit fails, we come
+ * back here).
+ * With recent USB stack (2.6.15+), I'm seeing that on
+ * hot unplug of the dongle...
+ * Lowest effective timer is 10ms...
+ * Jean II */
+ self->rx_defer_timer.function = &irda_usb_rx_defer_expired;
+ self->rx_defer_timer.data = (unsigned long) urb;
+ mod_timer(&self->rx_defer_timer, jiffies + (10 * HZ / 1000));
+ return;
}
/* Check for empty frames */
if (urb->actual_length <= USB_IRDA_HEADER) {
- WARNING("%s(), empty frame!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__);
goto done;
}
dataskb->dev = self->netdev;
dataskb->mac.raw = dataskb->data;
dataskb->protocol = htons(ETH_P_IRDA);
+ len = dataskb->len;
netif_rx(dataskb);
/* Keep stats up to date */
- self->stats.rx_bytes += dataskb->len;
+ self->stats.rx_bytes += len;
self->stats.rx_packets++;
self->netdev->last_rx = jiffies;
* idle slot....
* Jean II */
/* Note : with this scheme, we could submit the idle URB before
- * processing the Rx URB. Another time... Jean II */
+ * processing the Rx URB. I don't think it would buy us anything as
+ * we are running in the USB thread context. Jean II */
+ next_urb = self->idle_rx_urb;
- /* 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 */
urb->context = NULL;
self->idle_rx_urb = urb;
+
+ /* Submit the idle URB to replace the URB we've just received.
+ * Do it last to avoid race conditions... Jean II */
+ irda_usb_submit(self, skb, next_urb);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * In case of errors, we want the USB layer to have time to recover.
+ * Now, it is time to resubmit ouur Rx URB...
+ */
+static void irda_usb_rx_defer_expired(unsigned long data)
+{
+ struct urb *urb = (struct urb *) data;
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct irda_usb_cb *self;
+ struct irda_skb_cb *cb;
+ struct urb *next_urb;
+
+ IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+ /* Find ourselves */
+ cb = (struct irda_skb_cb *) skb->cb;
+ IRDA_ASSERT(cb != NULL, return;);
+ self = (struct irda_usb_cb *) cb->context;
+ IRDA_ASSERT(self != NULL, return;);
+
+ /* Same stuff as when Rx is done, see above... */
+ next_urb = self->idle_rx_urb;
+ urb->context = NULL;
+ self->idle_rx_urb = urb;
+ irda_usb_submit(self, skb, next_urb);
}
/*------------------------------------------------------------------*/
IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
- ASSERT(netdev != NULL, return -1;);
+ IRDA_ASSERT(netdev != NULL, return -1;);
self = (struct irda_usb_cb *) netdev->priv;
- ASSERT(self != NULL, return -1;);
+ IRDA_ASSERT(self != NULL, return -1;);
/* Can only open the device if it's there */
if(!self->present) {
- WARNING("%s(), device not present!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);
return -1;
}
*/
sprintf(hwname, "usb#%d", self->usbdev->devnum);
self->irlap = irlap_open(netdev, &self->qos, hwname);
- ASSERT(self->irlap != NULL, return -1;);
+ IRDA_ASSERT(self->irlap != NULL, return -1;);
/* Allow IrLAP to send data to us */
netif_start_queue(netdev);
if (!skb) {
/* If this ever happen, we are in deep s***.
* Basically, we can't start the Rx path... */
- WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
+ IRDA_WARNING("%s(), Failed to allocate Rx skb\n",
+ __FUNCTION__);
return -1;
}
//skb_reserve(newskb, USB_IRDA_HEADER - 1);
IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
- ASSERT(netdev != NULL, return -1;);
+ IRDA_ASSERT(netdev != NULL, return -1;);
self = (struct irda_usb_cb *) netdev->priv;
- ASSERT(self != NULL, return -1;);
+ IRDA_ASSERT(self != NULL, return -1;);
/* Clear this flag *before* unlinking the urbs and *before*
* stopping the network Tx queue - Jean II */
/* Stop network Tx queue */
netif_stop_queue(netdev);
+ /* Kill defered Rx URB */
+ del_timer(&self->rx_defer_timer);
+
/* Deallocate all the Rx path buffers (URBs and skb) */
for (i = 0; i < IU_MAX_RX_URBS; i++) {
struct urb *urb = self->rx_urb[i];
struct sk_buff *skb = (struct sk_buff *) urb->context;
/* Cancel the receive command */
- usb_unlink_urb(urb);
+ usb_kill_urb(urb);
/* The skb is ours, free it */
if(skb) {
dev_kfree_skb(skb);
}
}
/* Cancel Tx and speed URB - need to be synchronous to avoid races */
- self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
- usb_unlink_urb(self->tx_urb);
- self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
- usb_unlink_urb(self->speed_urb);
+ usb_kill_urb(self->tx_urb);
+ usb_kill_urb(self->speed_urb);
/* Stop and remove instance of IrLAP */
if (self->irlap)
struct irda_usb_cb *self;
int ret = 0;
- ASSERT(dev != NULL, return -1;);
+ IRDA_ASSERT(dev != NULL, return -1;);
self = dev->priv;
- ASSERT(self != NULL, return -1;);
+ IRDA_ASSERT(self != NULL, return -1;);
IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
unregister_netdev(self->netdev);
/* Remove the speed buffer */
- if (self->speed_buff != NULL) {
- kfree(self->speed_buff);
- self->speed_buff = NULL;
- }
+ kfree(self->speed_buff);
+ self->speed_buff = NULL;
}
/********************** USB CONFIG SUBROUTINES **********************/
ep = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dir = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK;
attr = endpoint[i].desc.bmAttributes;
- psize = endpoint[i].desc.wMaxPacketSize;
+ psize = le16_to_cpu(endpoint[i].desc.wMaxPacketSize);
/* Is it a bulk endpoint ??? */
if(attr == USB_ENDPOINT_XFER_BULK) {
/* This is our interrupt endpoint */
self->bulk_int_ep = ep;
} else {
- ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
+ IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
}
}
}
IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
__FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
/* Should be 8, 16, 32 or 64 bytes */
- ASSERT(self->bulk_out_mtu == 64, ;);
+ IRDA_ASSERT(self->bulk_out_mtu == 64, ;);
return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));
}
IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, intf->altsetting->desc.bInterfaceNumber, desc,
- sizeof(*desc), msecs_to_jiffies(500));
+ sizeof(*desc), 500);
IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
if (ret < sizeof(*desc)) {
- WARNING("usb-irda: class_descriptor read %s (%d)\n",
- (ret<0) ? "failed" : "too short", ret);
+ IRDA_WARNING("usb-irda: class_descriptor read %s (%d)\n",
+ (ret<0) ? "failed" : "too short", ret);
}
else if (desc->bDescriptorType != USB_DT_IRDA) {
- WARNING("usb-irda: bad class_descriptor type\n");
+ IRDA_WARNING("usb-irda: bad class_descriptor type\n");
}
else {
#ifdef IU_DUMP_CLASS_DESC
* don't need to check if the dongle is really ours.
* Jean II */
- MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
- dev->devnum, dev->descriptor.idVendor,
- dev->descriptor.idProduct);
+ IRDA_MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
net = alloc_irdadev(sizeof(*self));
if (!net)
goto err_out;
+ SET_MODULE_OWNER(net);
+ SET_NETDEV_DEV(net, &intf->dev);
self = net->priv;
self->netdev = net;
spin_lock_init(&self->lock);
-
- SET_MODULE_OWNER(net);
+ init_timer(&self->rx_defer_timer);
/* Create all of the needed urbs */
for (i = 0; i < IU_MAX_RX_URBS; i++) {
interface = intf->cur_altsetting;
if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->desc.bNumEndpoints)) {
- ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
+ IRDA_ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
ret = -EIO;
goto err_out_3;
}
if (ret)
goto err_out_4;
- MESSAGE("IrDA: Registered device %s\n", net->name);
+ IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
usb_set_intfdata(intf, self);
return 0;
* This will stop/desactivate the Tx path. - Jean II */
self->present = 0;
+ /* Kill defered Rx URB */
+ del_timer(&self->rx_defer_timer);
+
/* We need to have irq enabled to unlink the URBs. That's OK,
* at this point the Tx path is gone - Jean II */
spin_unlock_irqrestore(&self->lock, flags);
/* Accept no more transmissions */
/*netif_device_detach(self->netdev);*/
netif_stop_queue(self->netdev);
- /* Stop all the receive URBs */
+ /* Stop all the receive URBs. Must be synchronous. */
for (i = 0; i < IU_MAX_RX_URBS; i++)
- usb_unlink_urb(self->rx_urb[i]);
+ usb_kill_urb(self->rx_urb[i]);
/* Cancel Tx and speed URB.
- * Toggle flags to make sure it's synchronous. */
- self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
- usb_unlink_urb(self->tx_urb);
- self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
- usb_unlink_urb(self->speed_urb);
+ * Make sure it's synchronous to avoid races. */
+ usb_kill_urb(self->tx_urb);
+ usb_kill_urb(self->speed_urb);
}
/* Cleanup the device stuff */
* USB device callbacks
*/
static struct usb_driver irda_driver = {
- .owner = THIS_MODULE,
.name = "irda-usb",
.probe = irda_usb_probe,
.disconnect = irda_usb_disconnect,
if (ret < 0)
return ret;
- MESSAGE("USB IrDA support registered\n");
+ IRDA_MESSAGE("USB IrDA support registered\n");
return 0;
}
module_init(usb_irda_init);
/*
* Module parameters
*/
-MODULE_PARM(qos_mtt_bits, "i");
+module_param(qos_mtt_bits, int, 0);
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver");