📄 irda-usb.c
字号:
/* Trying to a turnaround time at this level is trying to measure * processor clock cycle with a wrist-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; do_gettimeofday(&self->now); diff = self->now.tv_usec - self->stamp.tv_usec;#ifdef IU_USB_MIN_RTT /* Factor in USB delays -> Get rid of udelay() that * would be lost in the noise - Jean II */ diff += IU_USB_MIN_RTT;#endif /* IU_USB_MIN_RTT */ /* If the usec counter did wraparound, the diff will * go negative (tv_usec is a long), so we need to * correct it by one second. Jean II */ 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); } } } /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */ if ((res = usb_submit_urb(urb, GFP_ATOMIC))) { 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);*/ } else { /* Increment packet stats */ self->stats.tx_packets++; self->stats.tx_bytes += skb->len; netdev->trans_start = jiffies; } spin_unlock_irqrestore(&self->lock, flags); return 0;drop: /* Drop silently the skb and exit */ dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); return err; /* Usually 1 */}/*------------------------------------------------------------------*//* * Note : this function will be called only for tx_urb... */static void write_bulk_callback(struct urb *urb){ unsigned long flags; struct sk_buff *skb = urb->context; struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* We should always have a context */ IRDA_ASSERT(self != NULL, return;); /* We should always be called for the speed URB */ IRDA_ASSERT(urb == self->tx_urb, return;); /* Free up the skb */ dev_kfree_skb_any(skb); urb->context = NULL; /* Check for timeout and other USB nasties */ if (urb->status != 0) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, urb->status, urb->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 */ //urb->status = 0; -> tested above /* Make sure we read self->present properly */ spin_lock_irqsave(&self->lock, flags); /* If the network is closed, stop everything */ if ((!self->netopen) || (!self->present)) { IRDA_DEBUG(0, "%s(), Network is gone...\n", __FUNCTION__); spin_unlock_irqrestore(&self->lock, flags); return; } /* If changes to speed or xbofs is pending... */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { if ((self->new_speed != self->speed) || (self->new_xbofs != self->xbofs)) { /* We haven't changed speed yet (because of * IUC_SPEED_BUG), so do it now - Jean II */ IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__); irda_usb_change_speed_xbofs(self); } else { /* New speed and xbof is now commited in hardware */ self->new_speed = -1; self->new_xbofs = -1; /* Done, waiting for next packet */ netif_wake_queue(self->netdev); } } else { /* Otherwise, allow the stack to send more packets */ netif_wake_queue(self->netdev); } spin_unlock_irqrestore(&self->lock, flags);}/*------------------------------------------------------------------*//* * 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){ unsigned long flags; struct irda_usb_cb *self = netdev->priv; struct urb *urb; int done = 0; /* If we have made any progress */ IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__); 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) { IRDA_WARNING("%s(), device not present!\n", __FUNCTION__); netif_stop_queue(netdev); spin_unlock_irqrestore(&self->lock, flags); return; } /* Check speed URB */ urb = self->speed_urb; if (urb->status != 0) { IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags); switch (urb->status) { case -EINPROGRESS: usb_unlink_urb(urb); /* Note : above will *NOT* call netif_wake_queue() * in completion handler, we will come back here. * Jean II */ done = 1; break; case -ECONNRESET: case -ENOENT: /* urb unlinked by us */ default: /* ??? - Play safe */ urb->status = 0; netif_wake_queue(self->netdev); done = 1; break; } } /* Check Tx URB */ urb = self->tx_urb; if (urb->status != 0) { struct sk_buff *skb = urb->context; IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags); /* Increase error count */ self->stats.tx_errors++;#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 */ switch (urb->status) { case -EINPROGRESS: usb_unlink_urb(urb); /* Note : above will *NOT* call netif_wake_queue() * in completion handler, because urb->status will * be -ENOENT. We will fix that at the next watchdog, * leaving more time to USB to recover... * Jean II */ done = 1; break; case -ECONNRESET: case -ENOENT: /* urb unlinked by us */ default: /* ??? - Play safe */ if(skb != NULL) { dev_kfree_skb_any(skb); urb->context = NULL; } urb->status = 0; netif_wake_queue(self->netdev); done = 1; break; } } spin_unlock_irqrestore(&self->lock, flags); /* Maybe we need a reset */ /* Note : Some drivers seem to use a usb_set_interface() when they * need to reset the hardware. Hum... */ /* if(done == 0) */}/************************* RECEIVE ROUTINES *************************//* * Receive packets from the USB layer stack and pass them to the IrDA stack. * Try to work around USB failures... *//* * Note : * Some of you may have noticed that most dongle have an interrupt in pipe * that we don't use. Here is the little secret... * When we hang a Rx URB on the bulk in pipe, it generates some USB traffic * in every USB frame. This is unnecessary overhead. * The interrupt in pipe will generate an event every time a packet is * received. Reading an interrupt pipe adds minimal overhead, but has some * latency (~1ms). * If we are connected (speed != 9600), we want to minimise latency, so * we just always hang the Rx URB and ignore the interrupt. * If we are not connected (speed == 9600), there is usually no Rx traffic, * and we want to minimise the USB overhead. In this case we should wait * 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 *//*------------------------------------------------------------------*//* * Submit a Rx URB to the USB layer to handle reception of a frame * Mostly called by the completion callback of the previous URB. * * Jean II */static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb){ struct irda_skb_cb *cb; int ret; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* This should never happen */ IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(urb != NULL, return;); /* Save ourselves in the skb */ cb = (struct irda_skb_cb *) skb->cb; cb->context = self; /* Reinitialize URB */ usb_fill_bulk_urb(urb, self->usbdev, usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), skb->data, IRDA_SKB_MAX_MTU, irda_usb_receive, skb); urb->status = 0; /* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */ ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ IRDA_WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret); }}/*------------------------------------------------------------------*//* * Function irda_usb_receive(urb) * * Called by the USB subsystem when a frame has been received * */static void irda_usb_receive(struct urb *urb){ struct sk_buff *skb = (struct sk_buff *) urb->context; struct irda_usb_cb *self; struct irda_skb_cb *cb; struct sk_buff *newskb; struct sk_buff *dataskb; 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; IRDA_ASSERT(cb != NULL, return;); self = (struct irda_usb_cb *) cb->context; IRDA_ASSERT(self != NULL, return;); /* If the network is closed or the device gone, stop everything */ if ((!self->netopen) || (!self->present)) { IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__); /* Don't re-submit the URB : will stall the Rx path */ return; } /* Check the status */ if (urb->status != 0) { switch (urb->status) { case -EILSEQ: self->stats.rx_crc_errors++; /* Also precursor to a hot-unplug on UHCI. */ /* Fallthrough... */ case -ECONNRESET: /* 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 */ case -ESHUTDOWN: /* That's usually a hot-unplug. Submit will fail... */ case -ETIME: /* Usually precursor to a hot-unplug on OHCI. */ default: self->stats.rx_errors++; IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags); break; } /* 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 <= self->header_length) { IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; } /* * Remember the time we received this frame, so we can * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ do_gettimeofday(&self->stamp); /* Check if we need to copy the data to a new skb or not. * For most frames, we use ZeroCopy and pass the already * allocated skb up the stack. * If the frame is small, it is more efficient to copy it * to save memory (copy will be fast anyway - that's * called Rx-copy-break). Jean II */ docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); /* Allocate a new skb */ if (self->capability & IUC_STIR421X) newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_STIR421X_HEADER); else newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); if (!newskb) { self->stats.rx_dropped++; /* We could deliver the current skb, but this would stall * the Rx path. Better drop the packet... Jean II */ goto done; } /* Make sure IP header get aligned (IrDA header is 5 bytes) */ /* But IrDA-USB header is 1 byte. Jean II */ //skb_reserve(newskb, USB_IRDA_HEADER - 1); if(docopy) { /* Copy packet, so we can recycle the original */ memcpy(newskb->data, skb->data, urb->actual_length); /* Deliver this new skb */ dataskb = newskb; /* And hook the old skb to the URB * Note : we don't need to "clean up" the old skb, * as we never touched it. Jean II */ } else { /* We are using ZeroCopy. Deliver old skb */ dataskb = skb; /* And hook the new skb to the URB */ skb = newskb; } /* Set proper length on skb & remove USB-IrDA header */ skb_put(dataskb, urb->actual_length); skb_pull(dataskb, self->header_length); /* Ask the networking layer to queue the packet for the IrDA stack */ 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 += len; self->stats.rx_packets++; self->netdev->last_rx = jiffies;done: /* Note : at this point, the URB we've just received (urb) * 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. 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; /* 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -