⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hfa384x_usb.c

📁 uClinux2.6上兼容PRISM2.0芯片组的USB设备驱动程序.
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -