blob: c86976a0eab50f19aade8a77642fb8336c157524 [file] [log] [blame]
/***********************************************************************
** Copyright (C) 2003 ACX100 Open Source Project
**
** 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 ACX100 Open Source Project can be
** made directly to:
**
** acx100-users@lists.sf.net
** http://acx100.sf.net
** ---------------------------------------------------------------------
*/
/***********************************************************************
** LOGGING
**
** - Avoid SHOUTING needlessly. Avoid excessive verbosity.
** Gradually remove messages which are old debugging aids.
**
** - Use printk() for messages which are to be always logged.
** Supply either 'acx:' or '<devname>:' prefix so that user
** can figure out who's speaking among other kernel chatter.
** acx: is for general issues (e.g. "acx: no firmware image!")
** while <devname>: is related to a particular device
** (think about multi-card setup). Double check that message
** is not confusing to the average user.
**
** - use printk KERN_xxx level only if message is not a WARNING
** but is INFO, ERR etc.
**
** - Use printk_ratelimited() for messages which may flood
** (e.g. "rx DUP pkt!").
**
** - Use log() for messages which may be omitted (and they
** _will_ be omitted in non-debug builds). Note that
** message levels may be disabled at compile-time selectively,
** thus select them wisely. Example: L_DEBUG is the lowest
** (most likely to be compiled out) -> use for less important stuff.
**
** - Do not print important stuff with log(), or else people
** will never build non-debug driver.
**
** Style:
** hex: capital letters, zero filled (e.g. 0x02AC)
** str: dont start from capitals, no trailing periods ("tx: queue is stopped")
*/
#if ACX_DEBUG > 1
void acx_log_fn_enter(const char *funcname);
void acx_log_fn_exit(const char *funcname);
void acx_log_fn_exit_v(const char *funcname, int v);
#define FN_ENTER \
do { \
if (unlikely(acx_debug & L_FUNC)) { \
acx_log_fn_enter(__func__); \
} \
} while (0)
#define FN_EXIT1(v) \
do { \
if (unlikely(acx_debug & L_FUNC)) { \
acx_log_fn_exit_v(__func__, v); \
} \
} while (0)
#define FN_EXIT0 \
do { \
if (unlikely(acx_debug & L_FUNC)) { \
acx_log_fn_exit(__func__); \
} \
} while (0)
#else
#define FN_ENTER
#define FN_EXIT1(v)
#define FN_EXIT0
#endif /* ACX_DEBUG > 1 */
#if ACX_DEBUG
#define log(chan, args...) \
do { \
if (acx_debug & (chan)) \
printk(args); \
} while (0)
#define printk_ratelimited(args...) printk(args)
#else /* Non-debug build: */
#define log(chan, args...)
/* Standard way of log flood prevention */
#define printk_ratelimited(args...) \
do { \
if (printk_ratelimit()) \
printk(args); \
} while (0)
#endif /* ACX_DEBUG */
void acx_print_mac(const char *head, const u8 *mac, const char *tail);
/* Optimized out to nothing in non-debug build */
static inline void
acxlog_mac(int level, const char *head, const u8 *mac, const char *tail)
{
if (acx_debug & level) {
acx_print_mac(head, mac, tail);
}
}
/***********************************************************************
** MAC address helpers
*/
static inline void
MAC_COPY(u8 *mac, const u8 *src)
{
*(u32*)mac = *(u32*)src;
((u16*)mac)[2] = ((u16*)src)[2];
/* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */
}
static inline void
MAC_FILL(u8 *mac, u8 val)
{
memset(mac, val, ETH_ALEN);
}
static inline void
MAC_BCAST(u8 *mac)
{
((u16*)mac)[2] = *(u32*)mac = -1;
}
static inline void
MAC_ZERO(u8 *mac)
{
((u16*)mac)[2] = *(u32*)mac = 0;
}
static inline int
mac_is_equal(const u8 *a, const u8 *b)
{
/* can't beat this */
return memcmp(a, b, ETH_ALEN) == 0;
}
static inline int
mac_is_bcast(const u8 *mac)
{
/* AND together 4 first bytes with sign-extended 2 last bytes
** Only bcast address gives 0xffffffff. +1 gives 0 */
return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0;
}
static inline int
mac_is_zero(const u8 *mac)
{
return ( *(u32*)mac | ((u16*)mac)[2] ) == 0;
}
static inline int
mac_is_directed(const u8 *mac)
{
return (mac[0] & 1)==0;
}
static inline int
mac_is_mcast(const u8 *mac)
{
return (mac[0] & 1) && !mac_is_bcast(mac);
}
#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
#define MAC(bytevector) \
((unsigned char *)bytevector)[0], \
((unsigned char *)bytevector)[1], \
((unsigned char *)bytevector)[2], \
((unsigned char *)bytevector)[3], \
((unsigned char *)bytevector)[4], \
((unsigned char *)bytevector)[5]
/***********************************************************************
** Random helpers
*/
#define TO_STRING(x) #x
#define STRING(x) TO_STRING(x)
#define CLEAR_BIT(val, mask) ((val) &= ~(mask))
#define SET_BIT(val, mask) ((val) |= (mask))
/* undefined if v==0 */
static inline unsigned int
lowest_bit(u16 v)
{
unsigned int n = 0;
while (!(v & 0xf)) { v>>=4; n+=4; }
while (!(v & 1)) { v>>=1; n++; }
return n;
}
/* undefined if v==0 */
static inline unsigned int
highest_bit(u16 v)
{
unsigned int n = 0;
while (v>0xf) { v>>=4; n+=4; }
while (v>1) { v>>=1; n++; }
return n;
}
/* undefined if v==0 */
static inline int
has_only_one_bit(u16 v)
{
return ((v-1) ^ v) >= v;
}
static inline int
is_hidden_essid(char *essid)
{
return '\0' == essid[0]
|| (' ' == essid[0] && '\0' == essid[1]);
}
/***********************************************************************
** LOCKING
** We have adev->sem and adev->lock.
**
** We employ following naming convention in order to get locking right:
**
** acx_e_xxxx - external entry points called from process context.
** It is okay to sleep. adev->sem is to be taken on entry.
** acx_i_xxxx - external entry points possibly called from atomic context.
** Sleeping is not allowed (and thus down(sem) is not legal!)
** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock!
** acx_l_xxxx - functions which expect lock to be already taken.
** rest - non-sleeping functions which do not require locking
** but may be run under lock
**
** A small number of local helpers do not have acx_[eisl]_ prefix.
** They are always close to caller and are to be reviewed locally.
**
** Theory of operation:
**
** All process-context entry points (_e_ functions) take sem
** immediately. IRQ handler and other 'atomic-context' entry points
** (_i_ functions) take lock immediately on entry, but dont take sem
** because that might sleep.
**
** Thus *all* code is either protected by sem or lock, or both.
**
** Code which must not run concurrently with IRQ takes lock.
** Such code is marked with _l_.
**
** This results in the following rules of thumb useful in code review:
**
** + If a function calls _s_ fn, it must be an _s_ itself.
** + You can call _l_ fn only (a) from another _l_ fn
** or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_,
** and dropping lock.
** + All IRQ code runs under lock.
** + Any _s_ fn is running under sem.
** + Code under sem can race only with IRQ code.
** + Code under sem+lock cannot race with anything.
*/
/* These functions *must* be inline or they will break horribly on SPARC, due
* to its weird semantics for save/restore flags */
#if defined(PARANOID_LOCKING) /* Lock debugging */
void acx_lock_debug(acx_device_t *adev, const char* where);
void acx_unlock_debug(acx_device_t *adev, const char* where);
void acx_down_debug(acx_device_t *adev, const char* where);
void acx_up_debug(acx_device_t *adev, const char* where);
void acx_lock_unhold(void);
void acx_sem_unhold(void);
static inline void
acx_lock_helper(acx_device_t *adev, unsigned long *fp, const char* where)
{
acx_lock_debug(adev, where);
spin_lock_irqsave(&adev->lock, *fp);
}
static inline void
acx_unlock_helper(acx_device_t *adev, unsigned long *fp, const char* where)
{
acx_unlock_debug(adev, where);
spin_unlock_irqrestore(&adev->lock, *fp);
}
static inline void
acx_down_helper(acx_device_t *adev, const char* where)
{
acx_down_debug(adev, where);
}
static inline void
acx_up_helper(acx_device_t *adev, const char* where)
{
acx_up_debug(adev, where);
}
#define acx_lock(adev, flags) acx_lock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__))
#define acx_unlock(adev, flags) acx_unlock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__))
#define acx_sem_lock(adev) acx_down_helper(adev, __FILE__ ":" STRING(__LINE__))
#define acx_sem_unlock(adev) acx_up_helper(adev, __FILE__ ":" STRING(__LINE__))
#elif defined(DO_LOCKING)
#define acx_lock(adev, flags) spin_lock_irqsave(&adev->lock, flags)
#define acx_unlock(adev, flags) spin_unlock_irqrestore(&adev->lock, flags)
#define acx_sem_lock(adev) down(&adev->sem)
#define acx_sem_unlock(adev) up(&adev->sem)
#define acx_lock_unhold() ((void)0)
#define acx_sem_unhold() ((void)0)
#else /* no locking! :( */
#define acx_lock(adev, flags) ((void)0)
#define acx_unlock(adev, flags) ((void)0)
#define acx_sem_lock(adev) ((void)0)
#define acx_sem_unlock(adev) ((void)0)
#define acx_lock_unhold() ((void)0)
#define acx_sem_unhold() ((void)0)
#endif
/***********************************************************************
*/
/* Can race with rx path (which is not protected by sem):
** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue()
** Can race with tx_complete IRQ:
** IRQ -> acxpci_l_clean_txdesc -> acx_wake_queue
** Review carefully all callsites */
static inline void
acx_stop_queue(struct net_device *ndev, const char *msg)
{
if (netif_queue_stopped(ndev))
return;
netif_stop_queue(ndev);
if (msg)
log(L_BUFT, "tx: stop queue %s\n", msg);
}
static inline int
acx_queue_stopped(struct net_device *ndev)
{
return netif_queue_stopped(ndev);
}
/*
static inline void
acx_start_queue(struct net_device *ndev, const char *msg)
{
netif_start_queue(ndev);
if (msg)
log(L_BUFT, "tx: start queue %s\n", msg);
}
*/
static inline void
acx_wake_queue(struct net_device *ndev, const char *msg)
{
netif_wake_queue(ndev);
if (msg)
log(L_BUFT, "tx: wake queue %s\n", msg);
}
static inline void
acx_carrier_off(struct net_device *ndev, const char *msg)
{
netif_carrier_off(ndev);
if (msg)
log(L_BUFT, "tx: carrier off %s\n", msg);
}
static inline void
acx_carrier_on(struct net_device *ndev, const char *msg)
{
netif_carrier_on(ndev);
if (msg)
log(L_BUFT, "tx: carrier on %s\n", msg);
}
/* This function does not need locking UNLESS you call it
** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
** wake queue. This can race with stop_queue elsewhere. */
void acx_set_status(acx_device_t *adev, u16 status);
/***********************************************************************
** Communication with firmware
*/
#define CMD_TIMEOUT_MS(n) (n)
#define ACX_CMD_TIMEOUT_DEFAULT CMD_TIMEOUT_MS(50)
#if ACX_DEBUG
/* We want to log cmd names */
#define acx_s_issue_cmd(adev, cmd, param, len) \
(adev)->ops.issue_cmd(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT, #cmd)
#define acx_s_issue_cmd_timeo(adev,cmd,param,len, timeout) \
(adev)->ops.issue_cmd(adev, cmd, param, len, timeout, #cmd)
int acx_s_configure_debug(acx_device_t *adev, void *pdr, int type, const char* str);
#define acx_s_configure(adev,pdr,type) \
acx_s_configure_debug(adev,pdr,type,#type)
int acx_s_interrogate_debug(acx_device_t *adev, void *pdr, int type, const char* str);
#define acx_s_interrogate(adev,pdr,type) \
acx_s_interrogate_debug(adev,pdr,type,#type)
#else
#define acx_s_issue_cmd(adev, cmd, param, len) \
(adev)->ops.issue_cmd(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT)
#define acx_s_issue_cmd_timeo(adev, cmd, param, len, timeout) \
(adev)->ops.issue_cmd(adev, cmd, param, len, timeout)
int acx_s_configure(acx_device_t *adev, void *pdr, int type);
int acx_s_interrogate(acx_device_t *adev, void *pdr, int type);
#endif
void acx_s_cmd_start_scan(acx_device_t *adev);
/***********************************************************************
** Ioctls
*/
int
acx111pci_ioctl_info(
struct net_device *ndev,
struct iw_request_info *info,
struct iw_param *vwrq,
char *extra);
int
acx100pci_ioctl_set_phy_amp_bias(
struct net_device *ndev,
struct iw_request_info *info,
struct iw_param *vwrq,
char *extra);
/***********************************************************************
** /proc
*/
#ifdef CONFIG_PROC_FS
int acx_proc_register_entries(const struct net_device *ndev);
int acx_proc_unregister_entries(const struct net_device *ndev);
#else
static inline int
acx_proc_register_entries(const struct net_device *ndev) { return OK; }
static inline int
acx_proc_unregister_entries(const struct net_device *ndev) { return OK; }
#endif
/***********************************************************************
*/
firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size);
int acxpci_s_upload_radio(acx_device_t *adev);
/***********************************************************************
** Unsorted yet :)
*/
#define acx_s_read_phy_reg(adev, reg, charbuf) \
(adev)->ops.read_phy_reg(adev, reg, charbuf)
#define acx_s_write_phy_reg(adev, reg, value) \
(adev)->ops.write_phy_reg(adev, reg, value)
#define acx_l_alloc_tx(adev) \
(adev)->ops.alloc_tx(adev)
#define acx_l_dealloc_tx(adev, tx_opaque) \
(adev)->ops.dealloc_tx(tx_opaque)
#define acx_l_get_txbuf(adev, tx_opaque) \
(adev)->ops.get_txbuf(adev, tx_opaque)
#define acx_l_tx_data(adev, tx_opaque, len) \
(adev)->ops.tx_data(adev, tx_opaque, len)
static inline struct ieee80211_hdr_3addr*
acx_get_wlan_hdr(acx_device_t *adev, const rxbuffer_t *rxbuf)
{
return (struct ieee80211_hdr_3addr*)((u8*)&rxbuf->hdr_a3 + adev->phy_header_len);
}
void acxpci_l_power_led(acx_device_t *adev, int enable);
int acxpci_read_eeprom_byte(acx_device_t *adev, u32 addr, u8 *charbuf);
unsigned int acxpci_l_clean_txdesc(acx_device_t *adev);
void acxpci_l_clean_txdesc_emergency(acx_device_t *adev);
int acxpci_s_create_hostdesc_queues(acx_device_t *adev);
void acxpci_create_desc_queues(acx_device_t *adev, u32 tx_queue_start, u32 rx_queue_start);
void acxpci_free_desc_queues(acx_device_t *adev);
char* acxpci_s_proc_diag_output(char *p, acx_device_t *adev);
int acxpci_proc_eeprom_output(char *p, acx_device_t *adev);
void acxpci_set_interrupt_mask(acx_device_t *adev);
int acx100pci_s_set_tx_level(acx_device_t *adev, u8 level_dbm);
void acx_s_msleep(int ms);
int acx_s_init_mac(acx_device_t *adev);
void acx_set_reg_domain(acx_device_t *adev, unsigned char reg_dom_id);
void acx_set_timer(acx_device_t *adev, int timeout_us);
void acx_update_capabilities(acx_device_t *adev);
void acx_s_start(acx_device_t *adev);
void acx_s_update_card_settings(acx_device_t *adev);
void acx_s_parse_configoption(acx_device_t *adev, const acx111_ie_configoption_t *pcfg);
void acx_l_update_ratevector(acx_device_t *adev);
void acx_init_task_scheduler(acx_device_t *adev);
void acx_schedule_task(acx_device_t *adev, unsigned int set_flag);
int acx_e_ioctl_old(struct net_device *ndev, struct ifreq *ifr, int cmd);
client_t *acx_l_sta_list_get(acx_device_t *adev, const u8 *address);
void acx_l_sta_list_del(acx_device_t *adev, client_t *clt);
int acx_l_transmit_disassoc(acx_device_t *adev, client_t *clt);
void acx_i_timer(unsigned long a);
int acx_s_complete_scan(acx_device_t *adev);
struct sk_buff *acx_rxbuf_to_ether(acx_device_t *adev, rxbuffer_t *rxbuf);
int acx_ether_to_txbuf(acx_device_t *adev, void *txbuf, const struct sk_buff *skb);
u8 acx_signal_determine_quality(u8 signal, u8 noise);
void acx_l_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf);
void acx_l_handle_txrate_auto(acx_device_t *adev, struct client *txc,
u16 intended_rate, u8 rate100, u16 rate111, u8 error,
int pkts_to_ignore);
void acx_dump_bytes(const void *, int);
u8 acx_rate111to100(u16);
void acx_s_set_defaults(acx_device_t *adev);
#if !ACX_DEBUG
static inline const char* acx_get_packet_type_string(u16 fc) { return ""; }
#else
const char* acx_get_packet_type_string(u16 fc);
#endif
const char* acx_cmd_status_str(unsigned int state);
int acx_i_start_xmit(struct sk_buff *skb, struct net_device *ndev);
void great_inquisitor(acx_device_t *adev);
void acx_s_get_firmware_version(acx_device_t *adev);
void acx_display_hardware_details(acx_device_t *adev);
int acx_e_change_mtu(struct net_device *ndev, int mtu);
struct net_device_stats* acx_e_get_stats(struct net_device *ndev);
struct iw_statistics* acx_e_get_wireless_stats(struct net_device *ndev);
int acx100_s_create_dma_regions(acx_device_t *);
int acx111_s_create_dma_regions(acx_device_t *);
int __init acxpci_e_init_module(void);
int __init acxusb_e_init_module(void);
void __exit acxpci_e_cleanup_module(void);
void __exit acxusb_e_cleanup_module(void);
int acx_i_ieee80211_start_xmit(struct ieee80211_txb *txb, struct net_device *ndev, int pri);
void acx_e_ieee80211_set_security(struct net_device *dev, struct ieee80211_security *sec);
void acx_e_ieee80211_set_chan(struct net_device *ndev, u8 channel);
void acx_l_softmac_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf);