📄 irda-usb.c
字号:
{ 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);}/*------------------------------------------------------------------*//* * 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 */}#define STIR421X_PATCH_PRODUCT_VER "Product Version: "#define STIR421X_PATCH_STMP_TAG "STMP"#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here *//* marks end of patch file header (PC DOS text file EOF character) */#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A#define STIR421X_PATCH_BLOCK_SIZE 1023/* * Function stir421x_fwupload (struct irda_usb_cb *self, * unsigned char *patch, * const unsigned int patch_len) * * Upload firmware code to SigmaTel 421X IRDA-USB dongle */static int stir421x_fw_upload(struct irda_usb_cb *self, unsigned char *patch, const unsigned int patch_len){ int ret = -ENOMEM; int actual_len = 0; unsigned int i; unsigned int block_size = 0; unsigned char *patch_block; patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL); if (patch_block == NULL) return -ENOMEM; /* break up patch into 1023-byte sections */ for (i = 0; i < patch_len; i += block_size) { block_size = patch_len - i; if (block_size > STIR421X_PATCH_BLOCK_SIZE) block_size = STIR421X_PATCH_BLOCK_SIZE; /* upload the patch section */ memcpy(patch_block, patch + i, block_size); ret = usb_bulk_msg(self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), patch_block, block_size, &actual_len, msecs_to_jiffies(500)); IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n", __FUNCTION__, actual_len, ret); if (ret < 0) break; } kfree(patch_block); return ret; }/* * Function stir421x_patch_device(struct irda_usb_cb *self) * * Get a firmware code from userspase using hotplug request_firmware() call */static int stir421x_patch_device(struct irda_usb_cb *self){ unsigned int i; int ret; char stir421x_fw_name[11]; const struct firmware *fw; unsigned char *fw_version_ptr; /* pointer to version string */ unsigned long fw_version = 0; /* * Known firmware patch file names for STIR421x dongles * are "42101001.sb" or "42101002.sb" */ sprintf(stir421x_fw_name, "4210%4X.sb", self->usbdev->descriptor.bcdDevice); ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev); if (ret < 0) return ret; /* We get a patch from userspace */ IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n", __FUNCTION__, stir421x_fw_name, fw->size); ret = -EINVAL; /* Get the bcd product version */ if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER, sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) { fw_version_ptr = fw->data + sizeof(STIR421X_PATCH_PRODUCT_VER) - 1; /* Let's check if the product version is dotted */ if (fw_version_ptr[3] == '.' && fw_version_ptr[7] == '.') { unsigned long major, minor, build; major = simple_strtoul(fw_version_ptr, NULL, 10); minor = simple_strtoul(fw_version_ptr + 4, NULL, 10); build = simple_strtoul(fw_version_ptr + 8, NULL, 10); fw_version = (major << 12) + (minor << 8) + ((build / 10) << 4) + (build % 10); IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n", __FUNCTION__, fw_version); } } if (self->usbdev->descriptor.bcdDevice == fw_version) { /* * If we're here, we've found a correct patch * The actual image starts after the "STMP" keyword * so forward to the firmware header tag */ for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG) && (i < fw->size); i++) ; /* here we check for the out of buffer case */ if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) && (i < STIR421X_PATCH_CODE_OFFSET)) { if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG, sizeof(STIR421X_PATCH_STMP_TAG) - 1)) { /* We can upload the patch to the target */ i += sizeof(STIR421X_PATCH_STMP_TAG); ret = stir421x_fw_upload(self, &fw->data[i], fw->size - i); } } } release_firmware(fw); return ret;}/********************** 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... *//*------------------------------------------------------------------*//* * 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, "%s()\n", __FUNCTION__); IRDA_ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; IRDA_ASSERT(self != NULL, return -1;); /* Can only open the device if it's there */ if(!self->present) { IRDA_WARNING("%s(), device not present!\n", __FUNCTION__); return -1; } if(self->needspatch) { IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; return -EIO ; } /* 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); IRDA_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++) { struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); if (!skb) { /* If this ever happen, we are in deep s***. * Basically, we can't start the Rx path... */ IRDA_WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__); return -1; } //skb_reserve(newskb, USB_IRDA_HEADER - 1); irda_usb_submit(self, skb, self->rx_urb[i]); } /* Ready to play !!! */ 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, "%s()\n", __FUNCTION__); IRDA_ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; IRDA_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); /* Kill defered Rx URB */ del_timer(&self->rx_defer_timer); /* Deallocate all the Rx path buffers (URBs and skb) */ for (i = 0; i < self->max_rx_urb; i++) { struct urb *urb = self->rx_urb[i]; struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ usb_kill_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 */ usb_kill_urb(self->tx_urb); usb_kill_urb(self->speed_urb); /* Stop and remove instance of IrLAP */ if (self->irlap) irlap_close(self->irlap); self->irlap = NULL; 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; IRDA_ASSERT(dev != NULL, return -1;); self = dev->priv; IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, 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, "%s()\n", __FUNCTION__); desc = self->irda_desc; /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); /* See spec section 7.2 for meaning. * Values are little endian (as most USB stuff), the IrDA stack * use it in native order (see parameters.c). - Jean II */ self->qos.baud_rate.bits = le16_to_cpu(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, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", __FUNCTION__, 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 &= 0x00ff; 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);}/*------------------------------------------------------------------*//* * 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 = self->netdev; IRDA_DEBUG(1, "%s()\n", __FUNCTION__); irda_usb_init_qos(self); /* Override the network functions we need to use */ 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; return register_netdev(netdev);}/*------------------------------------------------------------------*//* * Cleanup the network side of the irda-usb instance * Called when a USB instance is removed in irda_usb_disconnect() */static inline void irda_usb_close(struct irda_usb_cb *self){ IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Remove netdevice */ unregister_netdev(self->netdev); /* Remove the speed buffer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -