📄 hfa384x_usb.c
字号:
DBFENTER; result = -ENOLINK; if ( netif_running(netdev) ) { if ( !hw->wlandev->hwremoved && !test_bit(WORK_TX_HALT, &hw->usb_flags) ) { result = SUBMIT_URB(tx_urb, memflags); /* Test whether we need to reset the TX pipe */ if (result == -EPIPE) { WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", netdev->name); set_bit(WORK_TX_HALT, &hw->usb_flags); schedule_work(&hw->usb_work); } else if (result == 0) { netif_stop_queue(netdev); } } } DBFEXIT; return result;}/*----------------------------------------------------------------* hfa394x_usb_defer** There are some things that the USB stack cannot do while* in interrupt context, so we arrange this function to run* in process context.** Arguments:* hw device structure** Returns:* nothing** Call context:* process (by design)----------------------------------------------------------------*/static voidhfa384x_usb_defer(void *data){ hfa384x_t *hw = data; struct net_device *netdev = hw->wlandev->netdev; DBFENTER; /* Don't bother trying to reset anything if the plug * has been pulled ... */ if ( hw->wlandev->hwremoved ) { DBFEXIT; return; } /* Reception has stopped: try to reset the input pipe */ if (test_bit(WORK_RX_HALT, &hw->usb_flags)) { int ret; usb_kill_urb(&hw->rx_urb); /* Cannot be holding spinlock! */ if (hw->rx_urb_skb) { dev_kfree_skb(hw->rx_urb_skb); hw->rx_urb_skb = NULL; } ret = usb_clear_halt(hw->usb, hw->endp_in); if (ret != 0) { printk(KERN_ERR "Failed to clear rx pipe for %s: err=%d\n", netdev->name, ret); } else { printk(KERN_INFO "%s rx pipe reset complete.\n", netdev->name); clear_bit(WORK_RX_HALT, &hw->usb_flags); set_bit(WORK_RX_RESUME, &hw->usb_flags); } } /* Resume receiving data back from the device. */ if ( test_bit(WORK_RX_RESUME, &hw->usb_flags) ) { int ret; ret = submit_rx_urb(hw, GFP_KERNEL); if (ret != 0) { printk(KERN_ERR "Failed to resume %s rx pipe.\n", netdev->name); } else { clear_bit(WORK_RX_RESUME, &hw->usb_flags); } } /* Transmission has stopped: try to reset the output pipe */ if (test_bit(WORK_TX_HALT, &hw->usb_flags)) { int ret; usb_kill_urb(&hw->tx_urb); ret = usb_clear_halt(hw->usb, hw->endp_out); if (ret != 0) { printk(KERN_ERR "Failed to clear tx pipe for %s: err=%d\n", netdev->name, ret); } else { printk(KERN_INFO "%s tx pipe reset complete.\n", netdev->name); clear_bit(WORK_TX_HALT, &hw->usb_flags); set_bit(WORK_TX_RESUME, &hw->usb_flags); /* Stopping the BULK-OUT pipe also blocked * us from sending any more CTLX URBs, so * we need to re-run our queue ... */ hfa384x_usbctlxq_run(hw); } } /* Resume transmitting. */ if ( test_and_clear_bit(WORK_TX_RESUME, &hw->usb_flags) ) { p80211netdev_wake_queue(hw->wlandev); } DBFEXIT;}/*----------------------------------------------------------------* hfa384x_create** Sets up the hfa384x_t data structure for use. Note this* does _not_ intialize the actual hardware, just the data structures* we use to keep track of its state.** Arguments:* hw device structure* irq device irq number* iobase i/o base address for register access* membase memory base address for register access** Returns: * nothing** Side effects:** Call context:* process ----------------------------------------------------------------*/voidhfa384x_create( hfa384x_t *hw, struct usb_device *usb){ DBFENTER; memset(hw, 0, sizeof(hfa384x_t)); hw->usb = usb; /* set up the endpoints */ hw->endp_in = usb_rcvbulkpipe(usb, 1); hw->endp_out = usb_sndbulkpipe(usb, 2); /* Set up the waitq */ init_waitqueue_head(&hw->cmdq); /* Initialize the command queue */ spin_lock_init(&hw->ctlxq.lock); INIT_LIST_HEAD(&hw->ctlxq.pending); INIT_LIST_HEAD(&hw->ctlxq.active); INIT_LIST_HEAD(&hw->ctlxq.completing); INIT_LIST_HEAD(&hw->ctlxq.reapable); /* Initialize the authentication queue */ skb_queue_head_init(&hw->authq); tasklet_init(&hw->reaper_bh, hfa384x_usbctlx_reaper_task, (unsigned long)hw); tasklet_init(&hw->completion_bh, hfa384x_usbctlx_completion_task, (unsigned long)hw); INIT_WORK(&hw->link_bh, prism2sta_processing_defer, hw); INIT_WORK(&hw->usb_work, hfa384x_usb_defer, hw); init_timer(&hw->throttle); hw->throttle.function = hfa384x_usb_throttlefn; hw->throttle.data = (unsigned long)hw; init_timer(&hw->resptimer); hw->resptimer.function = hfa384x_usbctlx_resptimerfn; hw->resptimer.data = (unsigned long)hw; init_timer(&hw->reqtimer); hw->reqtimer.function = hfa384x_usbctlx_reqtimerfn; hw->reqtimer.data = (unsigned long)hw; usb_init_urb(&hw->rx_urb); usb_init_urb(&hw->tx_urb); usb_init_urb(&hw->ctlx_urb); hw->link_status = HFA384x_LINK_NOTCONNECTED; hw->state = HFA384x_STATE_INIT; INIT_WORK(&hw->commsqual_bh, prism2sta_commsqual_defer, hw); init_timer(&hw->commsqual_timer); hw->commsqual_timer.data = (unsigned long) hw; hw->commsqual_timer.function = prism2sta_commsqual_timer; DBFEXIT;}/*----------------------------------------------------------------* hfa384x_destroy** Partner to hfa384x_create(). This function cleans up the hw* structure so that it can be freed by the caller using a simple* kfree. Currently, this function is just a placeholder. If, at some* point in the future, an hw in the 'shutdown' state requires a 'deep'* kfree, this is where it should be done. Note that if this function* is called on a _running_ hw structure, the drvr_stop() function is* called.** Arguments:* hw device structure** Returns: * nothing, this function is not allowed to fail.** Side effects:** Call context:* process ----------------------------------------------------------------*/voidhfa384x_destroy( hfa384x_t *hw){ struct sk_buff *skb; DBFENTER; if ( hw->state == HFA384x_STATE_RUNNING ) { hfa384x_drvr_stop(hw); } hw->state = HFA384x_STATE_PREINIT; if (hw->scanresults) { kfree(hw->scanresults); hw->scanresults = NULL; } /* Now to clean out the auth queue */ while ( (skb = skb_dequeue(&hw->authq)) ) { dev_kfree_skb(skb); } DBFEXIT;}/*---------------------------------------------------------------- */static hfa384x_usbctlx_t* usbctlx_alloc(void){ hfa384x_usbctlx_t *ctlx; ctlx = kmalloc(sizeof(*ctlx), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (ctlx != NULL) { memset(ctlx, 0, sizeof(*ctlx)); init_MUTEX_LOCKED(&ctlx->wakeup); } return ctlx;}/*---------------------------------------------------------------- *----------------------------------------------------------------*/intusbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, hfa384x_cmdresult_t *result){ DBFENTER; result->status = hfa384x2host_16(cmdresp->status); result->resp0 = hfa384x2host_16(cmdresp->resp0); result->resp1 = hfa384x2host_16(cmdresp->resp1); result->resp2 = hfa384x2host_16(cmdresp->resp2); WLAN_LOG_DEBUG(4, "cmdresult:status=0x%04x " "resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", result->status, result->resp0, result->resp1, result->resp2); DBFEXIT; return (result->status & HFA384x_STATUS_RESULT);}voidusbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, hfa384x_rridresult_t *result){ DBFENTER; result->rid = hfa384x2host_16(rridresp->rid); result->riddata = rridresp->data; result->riddata_len = ((hfa384x2host_16(rridresp->frmlen) - 1) * 2); DBFEXIT;}/*----------------------------------------------------------------* Completor object:* This completor must be passed to hfa384x_usbctlx_complete_sync()* when processing a CTLX that returns a hfa384x_cmdresult_t structure.----------------------------------------------------------------*/struct usbctlx_cmd_completor{ usbctlx_completor_t head; const hfa384x_usb_cmdresp_t *cmdresp; hfa384x_cmdresult_t *result;};typedef struct usbctlx_cmd_completor usbctlx_cmd_completor_t;static int usbctlx_cmd_completor_fn(usbctlx_completor_t *head){ usbctlx_cmd_completor_t *complete = (usbctlx_cmd_completor_t*)head; return usbctlx_get_status(complete->cmdresp, complete->result);}static inline usbctlx_completor_t*init_cmd_completor(usbctlx_cmd_completor_t *completor, const hfa384x_usb_cmdresp_t *cmdresp, hfa384x_cmdresult_t *result){ completor->head.complete = usbctlx_cmd_completor_fn; completor->cmdresp = cmdresp; completor->result = result; return &(completor->head);}/*----------------------------------------------------------------* Completor object:* This completor must be passed to hfa384x_usbctlx_complete_sync()* when processing a CTLX that reads a RID.----------------------------------------------------------------*/struct usbctlx_rrid_completor{ usbctlx_completor_t head; const hfa384x_usb_rridresp_t *rridresp; void *riddata; UINT riddatalen;};typedef struct usbctlx_rrid_completor usbctlx_rrid_completor_t;static int usbctlx_rrid_completor_fn(usbctlx_completor_t *head){ usbctlx_rrid_completor_t *complete = (usbctlx_rrid_completor_t*)head; hfa384x_rridresult_t rridresult; usbctlx_get_rridresult(complete->rridresp, &rridresult); /* Validate the length, note body len calculation in bytes */ if ( rridresult.riddata_len != complete->riddatalen ) { WLAN_LOG_WARNING( "RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n", rridresult.rid, complete->riddatalen, rridresult.riddata_len); return -ENODATA; } memcpy(complete->riddata, rridresult.riddata, complete->riddatalen); return 0;}static inline usbctlx_completor_t*init_rrid_completor(usbctlx_rrid_completor_t *completor, const hfa384x_usb_rridresp_t *rridresp, void *riddata, UINT riddatalen){ completor->head.complete = usbctlx_rrid_completor_fn; completor->rridresp = rridresp; completor->riddata = riddata; completor->riddatalen = riddatalen; return &(completor->head);}/*----------------------------------------------------------------* Completor object:* Interprets the results of a synchronous RID-write----------------------------------------------------------------*/typedef usbctlx_cmd_completor_t usbctlx_wrid_completor_t;#define init_wrid_completor init_cmd_completor/*----------------------------------------------------------------* Completor object:* Interprets the results of a synchronous memory-write----------------------------------------------------------------*/typedef usbctlx_cmd_completor_t usbctlx_wmem_completor_t;#define init_wmem_completor init_cmd_completor/*----------------------------------------------------------------* Completor object:* Interprets the results of a synchronous memory-read----------------------------------------------------------------*/struct usbctlx_rmem_completor{ usbctlx_completor_t head; const hfa384x_usb_rmemresp_t *rmemresp; void *data; UINT len;};typedef struct usbctlx_rmem_completor usbctlx_rmem_completor_t;static int usbctlx_rmem_completor_fn(usbctlx_completor_t *head){ usbctlx_rmem_completor_t *complete = (usbctlx_rmem_completor_t*)head; WLAN_LOG_DEBUG(4,"rmemresp:len=%d\n", complete->rmemresp->frmlen); memcpy(complete->data, complete->rmemresp->data, complete->len); return 0;}static inline usbctlx_completor_t*init_rmem_completor(usbctlx_rmem_completor_t *completor, hfa384x_usb_rmemresp_t *rmemresp, void *data, UINT len){ completor->head.complete = usbctlx_rmem_completor_fn; completor->rmemresp = rmemresp; completor->data = data; completor->len = len; return &(completor->head);}/*----------------------------------------------------------------* hfa384x_cb_status** Ctlx_complete handler for async CMD type control exchanges.* mark the hw struct as such.** Note: If the handling is changed here, it should probably be * changed in docmd as well.** Arguments:* hw hw struct* ctlx completed CTLX** Returns: * nothing** Side effects:** Call context:* interrupt----------------------------------------------------------------*/voidhfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx){ DBFENTER; if ( ctlx->usercb != NULL ) { hfa384x_cmdresult_t cmdresult; if (ctlx->state != CTLX_COMPLETE) { memset(&cmdresult, 0, sizeof(cmdresult)); cmdresult.status = HFA384x_STATUS_RESULT_SET(HFA384x_CMD_ERR); } else { usbctlx_get_status(&ctlx->inbuf.cmdresp, &cmdresult); } ctlx->usercb(hw, &cmdresult, ctlx->usercb_data); } DBFEXIT;}/*----------------------------------------------------------------* hfa384x_cb_rrid** CTLX completion handler for async RRID type control exchanges.* * Note: If the handling is changed here, it should probably be * changed in dorrid as well.** Arguments:* hw hw struct* ctlx completed CTLX** Returns: * nothing** Side effects:*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -