📄 irda-usb.c
字号:
/* 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 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 (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))) { WARNING(__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; } 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 0;}/*------------------------------------------------------------------*//* * 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, __FUNCTION__ "()\n"); /* We should always have a context */ if (self == NULL) { WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); 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, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * 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, __FUNCTION__ "(), Network is gone...\n"); spin_unlock_irqrestore(&self->lock, flags); return; } /* If we need to change the speed or xbofs, do it now */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { IRDA_DEBUG(1, __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);}/*------------------------------------------------------------------*//* * 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, __FUNCTION__ "(), Network layer thinks we timed out!\n"); /* Protect us from USB callbacks, net Tx and else. */ spin_lock_irqsave(&self->lock, flags); if ((!self) || (!self->present)) { WARNING(__FUNCTION__ "(), device not present!\n"); 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 -ECONNABORTED: /* -103 */ case -ECONNRESET: /* -104 */ case -ETIMEDOUT: /* -110 */ case -ENOENT: /* -2 (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... * Also, we are in interrupt, so we need to have * USB_ASYNC_UNLINK to work properly... * Jean II */ done = 1; break; case -ECONNABORTED: /* -103 */ case -ECONNRESET: /* -104 */ case -ETIMEDOUT: /* -110 */ case -ENOENT: /* -2 (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 *//*------------------------------------------------------------------*//* * 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, struct urb *urb){ struct irda_skb_cb *cb; int ret; IRDA_DEBUG(2, __FUNCTION__ "()\n"); /* Check that we have an urb */ if (!urb) { WARNING(__FUNCTION__ "(), Bug : urb == NULL\n"); return; } /* Allocate new skb if it has not been recycled */ if (!skb) { skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1); if (!skb) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n"); return; } } else { /* Reset recycled skb */ skb->data = skb->tail = skb->head; skb->len = 0; } /* Make sure IP header get aligned (IrDA header is 5 bytes ) */ skb_reserve(skb, 1); /* Save ourselves */ cb = (struct irda_skb_cb *) skb->cb; cb->context = self; /* Reinitialize URB */ FILL_BULK_URB(urb, self->usbdev, usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), skb->data, skb->truesize, irda_usb_receive, skb); urb->transfer_flags = USB_QUEUE_BULK; /* Note : unlink *must* be synchronous because of the code in * irda_usb_net_close() -> free the skb - Jean II */ urb->status = 0; urb->next = NULL; /* Don't auto resubmit URBs */ /* 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... */ WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", 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 *new; IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length); /* Find ourselves */ cb = (struct irda_skb_cb *) skb->cb; ASSERT(cb != NULL, return;); self = (struct irda_usb_cb *) cb->context; ASSERT(self != NULL, return;); /* If the network is closed or the device gone, stop everything */ if ((!self->netopen) || (!self->present)) { IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n"); /* 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_errors++; self->stats.rx_crc_errors++; break; case -ECONNRESET: /* -104 */ IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->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: IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags); break; } goto done; } /* Check for empty frames */ if (urb->actual_length <= USB_IRDA_HEADER) { WARNING(__FUNCTION__ "(), empty frame!\n"); 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); /* Fix skb, and remove USB-IrDA header */ skb_put(skb, urb->actual_length); skb_pull(skb, USB_IRDA_HEADER); /* Don't waste a lot of memory on small IrDA frames */ if (skb->len < RX_COPY_THRESHOLD) { new = dev_alloc_skb(skb->len+1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -