📄 irda-usb.c
字号:
* 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 */ purb->transfer_flags |= USB_ZERO_PACKET; /* Timeout need to be shorter than NET watchdog timer */ purb->timeout = MSECS_TO_JIFFIES(200); /* 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 */ if ((res = usb_submit_urb(purb))) { 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 0;}/*------------------------------------------------------------------*//* * Note : this function will be called only for tx_urb... */static void write_bulk_callback(struct urb *purb){ unsigned long flags; struct sk_buff *skb = purb->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 */ if (self == NULL) { WARNING("%s(), Bug : self == NULL\n", __FUNCTION__); return; } /* Free up the skb */ dev_kfree_skb_any(skb); purb->context = NULL; /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, 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; -> 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 we need to change the speed or xbofs, do it now */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__); 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 *purb; int done = 0; /* If we have made any progress */ IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__); /* Protect us from USB callbacks, net Tx and else. */ spin_lock_irqsave(&self->lock, flags); if ((!self) || (!self->present)) { WARNING("%s(), device not present!\n", __FUNCTION__); netif_stop_queue(netdev); spin_unlock_irqrestore(&self->lock, flags); return; } /* Check speed URB */ purb = &(self->speed_urb); if (purb->status != USB_ST_NOERROR) { IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); switch (purb->status) { case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ usb_unlink_urb(purb); /* 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 */ purb->status = USB_ST_NOERROR; netif_wake_queue(self->netdev); done = 1; break; } } /* Check Tx URB */ purb = &(self->tx_urb); if (purb->status != USB_ST_NOERROR) { struct sk_buff *skb = purb->context; IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->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 (purb->status) { case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ usb_unlink_urb(purb); /* Note : above will *NOT* call netif_wake_queue() * in completion handler, because purb->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); purb->context = NULL; } purb->status = USB_ST_NOERROR; 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 *purb){ struct irda_skb_cb *cb; int ret; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* Check that we have an urb */ if (!purb) { WARNING("%s(), Bug : purb == NULL\n", __FUNCTION__); 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("%s(), Failed to allocate Rx skb\n", __FUNCTION__); 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(purb, self->usbdev, usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), skb->data, skb->truesize, irda_usb_receive, skb); purb->transfer_flags = USB_QUEUE_BULK; /* Note : unlink *must* be synchronous because of the code in * irda_usb_net_close() -> free the skb - Jean II */ purb->status = USB_ST_NOERROR; purb->next = NULL; /* Don't auto resubmit URBs */ ret = usb_submit_urb(purb); 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); }}/*------------------------------------------------------------------*//* * Function irda_usb_receive(purb) * * Called by the USB subsystem when a frame has been received * */static void irda_usb_receive(struct urb *purb) { struct sk_buff *skb = (struct sk_buff *) purb->context; struct irda_usb_cb *self; struct irda_skb_cb *cb; struct sk_buff *new; IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, purb->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, "%s(), Network is gone!\n", __FUNCTION__); /* Don't re-submit the URB : will stall the Rx path */ return; } /* Check the status */ 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: /* -104 */ IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, 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: IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, purb->status, purb->transfer_flags); break; } goto done; } /* Check for empty frames */ if (purb->actual_length <= USB_IRDA_HEADER) { WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -