📄 hfa384x_usb.c
字号:
/* src/prism2/driver/hfa384x_usb.c** Functions that talk to the USB variantof the Intersil hfa384x MAC** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.* --------------------------------------------------------------------** linux-wlan** The contents of this file are subject to the Mozilla Public* License Version 1.1 (the "License"); you may not use this file* except in compliance with the License. You may obtain a copy of* the License at http://www.mozilla.org/MPL/** Software distributed under the License is distributed on an "AS* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or* implied. See the License for the specific language governing* rights and limitations under the License.** Alternatively, the contents of this file may be used under the* terms of the GNU Public License version 2 (the "GPL"), in which* case the provisions of the GPL are applicable instead of the* above. If you wish to allow the use of your version of this file* only under the terms of the GPL and not to allow others to use* your version of this file under the MPL, indicate your decision* by deleting the provisions above and replace them with the notice* and other provisions required by the GPL. If you do not delete* the provisions above, a recipient may use your version of this* file under either the MPL or the GPL.** --------------------------------------------------------------------** Inquiries regarding the linux-wlan Open Source project can be* made directly to:** AbsoluteValue Systems Inc.* info@linux-wlan.com* http://www.linux-wlan.com** --------------------------------------------------------------------** Portions of the development of this software were funded by * Intersil Corporation as part of PRISM(R) chipset product development.** --------------------------------------------------------------------** This file implements functions that correspond to the prism2/hfa384x* 802.11 MAC hardware and firmware host interface.** The functions can be considered to represent several levels of * abstraction. The lowest level functions are simply C-callable wrappers* around the register accesses. The next higher level represents C-callable* prism2 API functions that match the Intersil documentation as closely* as is reasonable. The next higher layer implements common sequences * of invokations of the API layer (e.g. write to bap, followed by cmd).** Common sequences:* hfa384x_drvr_xxx Highest level abstractions provided by the * hfa384x code. They are driver defined wrappers * for common sequences. These functions generally* use the services of the lower levels.** hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These* functions are wrappers for the RID get/set * sequence. They call copy_[to|from]_bap() and * cmd_access(). These functions operate on the * RIDs and buffers without validation. The caller* is responsible for that.** API wrapper functions:* hfa384x_cmd_xxx functions that provide access to the f/w commands. * The function arguments correspond to each command* argument, even command arguments that get packed* into single registers. These functions _just_* issue the command by setting the cmd/parm regs* & reading the status/resp regs. Additional* activities required to fully use a command* (read/write from/to bap, get/set int status etc.)* are implemented separately. Think of these as* C-callable prism2 commands.** Lowest Layer Functions:* hfa384x_docmd_xxx These functions implement the sequence required* to issue any prism2 command. Primarily used by the* hfa384x_cmd_xxx functions.** hfa384x_bap_xxx BAP read/write access functions.* Note: we usually use BAP0 for non-interrupt context* and BAP1 for interrupt context.** hfa384x_dl_xxx download related functions.* * Driver State Issues:* Note that there are two pairs of functions that manage the* 'initialized' and 'running' states of the hw/MAC combo. The four* functions are create(), destroy(), start(), and stop(). create()* sets up the data structures required to support the hfa384x_** functions and destroy() cleans them up. The start() function gets* the actual hardware running and enables the interrupts. The stop()* function shuts the hardware down. The sequence should be:* create()* start()* .* . Do interesting things w/ the hardware* .* stop()* destroy()** Note that destroy() can be called without calling stop() first.* --------------------------------------------------------------------*//*================================================================*//* System Includes */#define WLAN_DBVAR prism2_debug#include <wlan/version.h>#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/wireless.h>#include <linux/netdevice.h>#include <linux/timer.h>#include <asm/semaphore.h>#include <asm/io.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/bitops.h>#include <linux/list.h>#include <linux/usb.h>#include <wlan/wlan_compat.h>#if (WLAN_HOSTIF != WLAN_USB)#error "This file is specific to USB"#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)static voidusb_init_urb(struct urb *urb){ memset(urb, 0, sizeof(*urb));#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */ urb->count = (atomic_t)ATOMIC_INIT(1);#endif spin_lock_init(&urb->lock);}#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */# define SUBMIT_URB(u,f) usb_submit_urb(u,f)#else# define SUBMIT_URB(u,f) usb_submit_urb(u)#endif/*================================================================*//* Project Includes */#include <wlan/p80211types.h>#include <wlan/p80211hdr.h>#include <wlan/p80211mgmt.h>#include <wlan/p80211conv.h>#include <wlan/p80211msg.h>#include <wlan/p80211netdev.h>#include <wlan/p80211req.h>#include <wlan/p80211metadef.h>#include <wlan/p80211metastruct.h>#include <prism2/hfa384x.h>#include <prism2/prism2mgmt.h>/*================================================================*//* Local Constants */enum cmd_mode{ DOWAIT = 0, DOASYNC};typedef enum cmd_mode CMD_MODE;#define THROTTLE_JIFFIES (HZ/8)/*================================================================*//* Local Macros */#define ROUNDUP64(a) (((a)+63)&~63)/*================================================================*//* Local Types *//*================================================================*//* Local Static Definitions */extern int prism2_debug;/*================================================================*//* Local Function Declarations */#ifdef DEBUG_USBstatic void dbprint_urb(struct urb* urb);#endifstatic voidhfa384x_int_rxmonitor( wlandevice_t *wlandev, hfa384x_usb_rxfrm_t *rxfrm);static voidhfa384x_usb_defer(void *hw);static intsubmit_rx_urb(hfa384x_t *hw, int flags);static intsubmit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, int flags);/*---------------------------------------------------*//* Callbacks */#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))static void hfa384x_usbout_callback(struct urb *urb);static voidhfa384x_ctlxout_callback(struct urb *urb);static void hfa384x_usbin_callback(struct urb *urb);#elsestatic void hfa384x_usbout_callback(struct urb *urb, struct pt_regs *regs);static voidhfa384x_ctlxout_callback(struct urb *urb, struct pt_regs *regs);static void hfa384x_usbin_callback(struct urb *urb, struct pt_regs *regs);#endifstatic voidhfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin);static voidhfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb);static voidhfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin);static voidhfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout);static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, int urb_status);/*---------------------------------------------------*//* Functions to support the prism2 usb command queue */static void hfa384x_usbctlxq_run(hfa384x_t *hw);static void hfa384x_usbctlx_reqtimerfn(unsigned long data);static void hfa384x_usbctlx_resptimerfn(unsigned long data);static voidhfa384x_usb_throttlefn(unsigned long data);static voidhfa384x_usbctlx_completion_task(unsigned long data);static voidhfa384x_usbctlx_reaper_task(unsigned long data);static inthfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx);static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx);struct usbctlx_completor{ int (*complete)(struct usbctlx_completor*);};typedef struct usbctlx_completor usbctlx_completor_t;static inthfa384x_usbctlx_complete_sync(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx, usbctlx_completor_t *completor);static intunlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx);static voidhfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx);static voidhfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx);static intusbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, hfa384x_cmdresult_t *result);static voidusbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, hfa384x_rridresult_t *result);/*---------------------------------------------------*//* Low level req/resp CTLX formatters and submitters */static inthfa384x_docmd( hfa384x_t *hw, CMD_MODE mode, hfa384x_metacmd_t *cmd, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);static inthfa384x_dorrid( hfa384x_t *hw, CMD_MODE mode, UINT16 rid, void *riddata, UINT riddatalen, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);static inthfa384x_dowrid( hfa384x_t *hw, CMD_MODE mode, UINT16 rid, void *riddata, UINT riddatalen, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);static inthfa384x_dormem( hfa384x_t *hw, CMD_MODE mode, UINT16 page, UINT16 offset, void *data, UINT len, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);static inthfa384x_dowmem( hfa384x_t *hw, CMD_MODE mode, UINT16 page, UINT16 offset, void *data, UINT len, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data);static inthfa384x_isgood_pdrcode(UINT16 pdrcode);/*================================================================*//* Function Definitions */static inline const char* ctlxstr(CTLX_STATE s){ static const char* ctlx_str[] = { "Initial state", "Complete", "Request failed", "Request pending", "Request packet submitted", "Request packet completed", "Response packet completed" }; return ctlx_str[s];};static inline hfa384x_usbctlx_t*get_active_ctlx(hfa384x_t *hw){ return list_entry(hw->ctlxq.active.next, hfa384x_usbctlx_t, list);}#ifdef DEBUG_USBvoiddbprint_urb(struct urb* urb){ WLAN_LOG_DEBUG(3,"urb->pipe=0x%08x\n", urb->pipe); WLAN_LOG_DEBUG(3,"urb->status=0x%08x\n", urb->status); WLAN_LOG_DEBUG(3,"urb->transfer_flags=0x%08x\n", urb->transfer_flags); WLAN_LOG_DEBUG(3,"urb->transfer_buffer=0x%08x\n", (UINT)urb->transfer_buffer); WLAN_LOG_DEBUG(3,"urb->transfer_buffer_length=0x%08x\n", urb->transfer_buffer_length); WLAN_LOG_DEBUG(3,"urb->actual_length=0x%08x\n", urb->actual_length); WLAN_LOG_DEBUG(3,"urb->bandwidth=0x%08x\n", urb->bandwidth); WLAN_LOG_DEBUG(3,"urb->setup_packet(ctl)=0x%08x\n", (UINT)urb->setup_packet); WLAN_LOG_DEBUG(3,"urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); WLAN_LOG_DEBUG(3,"urb->interval(irq)=0x%08x\n", urb->interval); WLAN_LOG_DEBUG(3,"urb->error_count(iso)=0x%08x\n", urb->error_count); WLAN_LOG_DEBUG(3,"urb->timeout=0x%08x\n", urb->timeout); WLAN_LOG_DEBUG(3,"urb->context=0x%08x\n", (UINT)urb->context); WLAN_LOG_DEBUG(3,"urb->complete=0x%08x\n", (UINT)urb->complete);}#endif/*----------------------------------------------------------------* submit_rx_urb** Listen for input data on the BULK-IN pipe. If the pipe has* stalled then schedule it to be reset.** Arguments:* hw device struct* memflags memory allocation flags** Returns:* error code from submission** Call context:* Any----------------------------------------------------------------*/static intsubmit_rx_urb(hfa384x_t *hw, int memflags){ struct sk_buff *skb; int result; DBFENTER; skb = dev_alloc_skb(sizeof(hfa384x_usbin_t)); if (skb == NULL) { result = -ENOMEM; goto done; } /* Post the IN urb */ usb_fill_bulk_urb(&hw->rx_urb, hw->usb, hw->endp_in, skb->data, sizeof(hfa384x_usbin_t), hfa384x_usbin_callback, hw->wlandev); hw->rx_urb_skb = skb; result = -ENOLINK; if ( !hw->wlandev->hwremoved && !test_bit(WORK_RX_HALT, &hw->usb_flags)) { result = SUBMIT_URB(&hw->rx_urb, memflags); /* Check whether we need to reset the RX pipe */ if (result == -EPIPE) { WLAN_LOG_WARNING("%s rx pipe stalled: requesting reset\n", hw->wlandev->netdev->name); if ( !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) schedule_work(&hw->usb_work); } } /* Don't leak memory if anything should go wrong */ if (result != 0) { dev_kfree_skb(skb); skb = NULL; hw->rx_urb_skb = NULL; } done: DBFEXIT; return result;}/*----------------------------------------------------------------* submit_tx_urb** Prepares and submits the URB of transmitted data. If the* submission fails then it will schedule the output pipe to* be reset.** Arguments:* hw device struct* tx_urb URB of data for tranmission* memflags memory allocation flags** Returns:* error code from submission** Call context:* Any----------------------------------------------------------------*/static intsubmit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, int memflags){ struct net_device *netdev = hw->wlandev->netdev; int result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -