📄 irda-usb.c
字号:
if (!new) { self->stats.rx_dropped++; goto done; } /* Make sure IP header get aligned (IrDA header is 5 bytes) */ skb_reserve(new, 1); /* 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() */ } else { /* Deliver the original skb */ new = skb; skb = NULL; } self->stats.rx_bytes += new->len; self->stats.rx_packets++; /* Ask the networking layer to queue the packet for the IrDA stack */ new->dev = self->netdev; new->mac.raw = new->data; new->protocol = htons(ETH_P_IRDA); netif_rx(new); 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. Another time... Jean II */ /* 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;}/*------------------------------------------------------------------*//* * 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(1, __FUNCTION__ "()\n"); /* Set up to be a normal IrDA network device driver */ irda_device_setup(dev); /* Insert overrides below this line! */ return 0;}/*------------------------------------------------------------------*//* * Function irda_usb_net_open (dev) * * Network device is taken up. Usually this is done by "ifconfig irda0 up" * * Note : don't mess with self->netopen - Jean II */static int irda_usb_net_open(struct net_device *netdev){ struct irda_usb_cb *self; char hwname[16]; int i; IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; ASSERT(self != NULL, return -1;); /* Can only open the device if it's there */ if(!self->present) { WARNING(__FUNCTION__ "(), device not present!\n"); return -1; } /* Initialise default speed and xbofs value * (IrLAP will change that soon) */ self->speed = -1; self->xbofs = -1; self->new_speed = -1; self->new_xbofs = -1; /* To do *before* submitting Rx urbs and starting net Tx queue * Jean II */ self->netopen = 1; /* * Now that everything should be initialized properly, * Open new IrLAP layer instance to take care of us... * Note : will send immediately a speed change... */ 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); /* We submit all the Rx URB except for one that we keep idle. * Need to be initialised before submitting other USBs, because * in some cases as soon as we submit the URBs the USB layer * will trigger a dummy receive - Jean II */ self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS]; self->idle_rx_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]); /* 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(1, __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++) { struct urb *urb = self->rx_urb[i]; struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ usb_unlink_urb(urb); /* The skb is ours, free it */ if(skb) { dev_kfree_skb(skb); urb->context = NULL; } } /* Cancel Tx and speed URB - need to be synchronous to avoid races */ self->tx_urb->transfer_flags &= ~USB_ASYNC_UNLINK; usb_unlink_urb(self->tx_urb); self->speed_urb->transfer_flags &= ~USB_ASYNC_UNLINK; 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){ unsigned long flags; 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); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Protect us from USB callbacks, net watchdog and else. */ spin_lock_irqsave(&self->lock, flags); /* Check if the device is still there */ if(self->present) { /* Set the desired speed */ self->new_speed = irq->ifr_baudrate; irda_usb_change_speed_xbofs(self); } spin_unlock_irqrestore(&self->lock, flags); break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Check if the IrDA stack is still there */ if(self->netopen) 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(1, __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 = 250*HZ/1000; /* 250 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(1, __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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -