📄 if_cf.c
字号:
/*
File : if_cf.c
*/
#include <pcmcia/cs_types.h>
#include <include.h>
#include "if_cf.h"
#define HP_RETRY (10000)
#define FW_RETRY (5000)
#define FW_BLOCK_SIZE (256)
#define CIS(X) \
do { \
tuple.DesiredTuple = X; \
\
if (CardServices(GetFirstTuple, handle, &tuple)) \
goto error; \
if (CardServices(GetTupleData, handle, &tuple)) \
goto error; \
\
cisbuf[ofs++] = tuple.TupleCode; \
cisbuf[ofs++] = tuple.TupleLink; \
memcpy(cisbuf+ofs, tuple.TupleData, tuple.TupleLink); \
ofs += tuple.TupleLink; \
} while (0)
#ifdef CF8381
#include "cf8381.h"
#endif
#ifdef CF8385
#ifdef RF8015
#include "cf8385.h"
#endif
#ifdef RF8031
#include "cf8385h.h"
#endif
#endif
#ifdef CF8305
#include "cf8305.h"
#endif
#ifdef HELPER_IMAGE
#include "helper.h"
#define init_image helper_image
#else
#define init_image fmimage
#endif
int *register_cf_driver(cf_notifier_fn_add ,cf_notifier_fn_remove , void *);
void unregister_cf_driver(void);
static u8 cf_int_cause = 0;
static dev_link_t cisinfo;
static int poll_reg(uint addr, u8 value, u32 retry, u32 usec)
{
u32 count;
for (count = 0; count < retry; count ++)
{
if (inb(addr) == value)
break;
udelay(usec);
}
return (count >= retry) ? -1: 0;
}
static void init_cf_addr(wlan_private *priv)
{
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
u32 base = priv->wlan_dev.netdev->base_addr;
reg->host.status = CF_HCR_HOST_STATUS + base;
reg->host.int_cause = CF_HCR_CARD_INT_CAUSE + base;
reg->host.int_mask = CF_HCR_HOST_INT_MASK + base;
reg->host.raddr0 = CF_HCR_READ_BASE_LOW + base;
reg->host.raddr1 = CF_HCR_READ_BASE_HIGH + base;
reg->host.waddr0 = CF_HCR_WRITE_BASE_LOW + base;
reg->host.waddr1 = CF_HCR_WRITE_BASE_HIGH + base;
reg->host.io_data_read = CF_HCR_IO_READ_PORT + base;
reg->host.io_cmd_read = CF_HCR_IO_CMD_READ_PORT + base;
reg->host.io_data_write_len = CF_HCR_IO_WRITE_LEN + base;
reg->host.io_data_write = CF_HCR_IO_WRITE_PORT + base;
reg->host.io_cmd_write_len = CF_HCR_IO_CMD_WRITE_LEN + base;
reg->host.io_cmd_write = CF_HCR_IO_CMD_WRITE_PORT + base;
reg->host.scratch = CF_HCR_SCRATCH_PORT + base;
reg->host.cis_addr = CF_HCR_CIS_ADDR_PORT + base;
reg->host.cis_data = CF_HCR_CIS_DATA_PORT + base;
reg->host.gbus_read = CF_HCR_IO_GBUS_REG_READ + base;
reg->host.gbus_write = CF_HCR_IO_GBUS_REG_WRITE + base;
reg->card.product_id = CF_CCR_PRODUCT_ID + base;
reg->card.status = CF_CCR_CARD_STATUS + base;
reg->card.int_cause = CF_CCR_HOST_INT_CAUSE + base;
reg->card.io_data_len = CF_CCR_IO_READ_LEN + base;
reg->card.sq_raddr0 = CF_CCR_SQ_READ_BASE_LOW + base;
reg->card.sq_raddr1 = CF_CCR_SQ_READ_BASE_HIGH + base;
reg->card.sq_waddr0 = CF_CCR_SQ_WRITE_BASE_LOW + base;
reg->card.sq_waddr1 = CF_CCR_SQ_WRITE_BASE_HIGH + base;
reg->card.io_cmd_read_len = CF_CCR_IO_CMD_READ_LEN + base;
reg->card.sq_cmd_raddr0 = CF_CCR_SQ_CMD_READ_BASE_LOW + base;
reg->card.sq_cmd_raddr1 = CF_CCR_SQ_CMD_READ_BASE_HIGH + base;
reg->card.sq_cmd_waddr0 = CF_CCR_SQ_CMD_WRITE_BASE_LOW + base;
reg->card.sq_cmd_waddr1 = CF_CCR_SQ_CMD_WRITE_BASE_HIGH + base;
reg->card.cfg_base = CF_CCR_CFG_REG_BASE_ADR + base;
reg->card.card_cfg = CF_CCR_CARD_CFG + base;
reg->card.scratch = CF_CCR_SCRATCH_PORT + base;
reg->card.tx_seq = CF_CCR_TX_FRAME_SEQ_NUM + base;
reg->card.tx_stat = CF_CCR_TX_FRAME_STATUS + base;
reg->card.int_mask = CF_CCR_CARD_INT_MASK + base;
reg->card.cis_addr = CF_CCR_CIS_ADR_PORT + base;
reg->card.cis_data = CF_CCR_CIS_DATA_PORT + base;
return;
}
static void cf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
wlan_private *priv = (wlan_private *) dev->priv;
wlan_adapter *Adapter = priv->adapter;
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
u16 cause;
int valid_interrupt = 0;
ENTER();
for (;;)
{
cause = inw(reg->card.int_cause);
PRINTK(" int_cause = 0x%02x @ %lu\n", cause, jiffies);
if (cause == 0xffff)
{
Adapter->SurpriseRemoved = TRUE;
break;
}
cause &= CF_CCR_HIC_MASK;
if (!cause)
{
PRINTK(" no interrupt\n");
break;
}
outw(cause, reg->card.int_cause);
valid_interrupt++;
if (cause & CF_CCR_HIC_TxDnLdRdy)
{
// priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
cf_int_cause |= HIS_TxDnLdRdy;
}
if (cause & CF_CCR_HIC_RxUpLdRdy)
cf_int_cause |= HIS_RxUpLdRdy;
if (cause & CF_CCR_HIC_CmdDnLdRdy)
cf_int_cause |= HIS_CmdDnLdRdy;
if (cause & CF_CCR_HIC_CmdRspRdy)
cf_int_cause |= HIS_CmdUpLdRdy;
if (cause & CF_CCR_HIC_CardEvent)
cf_int_cause |= HIS_CardEvent;
}
if (valid_interrupt || Adapter->SurpriseRemoved)
{
sbi_disable_host_int(priv, HIM_DISABLE);
PRINTK(" cf_int_cause = 0x%02X\n", cf_int_cause);
PRINTK(" adapter->HisRegCpy = 0x%02X\n", Adapter->HisRegCpy);
wlan_interrupt(dev);
}
LEAVE();
}
static int cf_send_cmd(wlan_private * priv, u16 * buf, u16 len)
{
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
ENTER();
if (cf_IsCmdReady(priv) != IX_STATUS_SUCCESS)
{
PRINTK(" device not ready!\n");
return IX_STATUS_DEVICE_BUSY;
}
outw(len, reg->host.io_cmd_write_len);
outsw(reg->host.io_cmd_write, buf, len / 2);
if (len & 0x0001)
outb(((u8 *)buf)[len - 1], reg->host.io_cmd_write);
cf_UshortRegSetBits(priv, CF_HCR_HOST_STATUS, CF_HCR_HS_CmdDnLdOvr);
wmb();
outw(CF_HCR_CIC_CmdDnLdOvr, reg->host.int_cause);
LEAVE();
return IX_STATUS_SUCCESS;
}
static int cf_tx_block(wlan_private *priv, u8 *buf, u16 len)
{
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
ENTER();
outw(len, reg->host.io_data_write_len);
outsw(reg->host.io_data_write, buf, len / 2);
if (len & 0x0001)
outb(buf[len - 1], reg->host.io_data_write);
priv->adapter->SeqNum++;
cf_UshortRegSetBits(priv, CF_HCR_HOST_STATUS, CF_HCR_HS_TxDnLdOvr);
cf_UshortRegSetBits(priv, CF_HCR_CARD_INT_CAUSE, CF_HCR_CIC_TxDnLdOvr);
LEAVE();
return 0;
}
int *sbi_register(wlan_notifier_fn_add add, wlan_notifier_fn_remove remove, void *arg)
{
return
register_cf_driver(
(cf_notifier_fn_add)add,
(cf_notifier_fn_remove)remove,
NULL
);
}
void sbi_unregister(void)
{
unregister_cf_driver();
}
int sbi_get_int_status(wlan_private * priv, u8 * ireg)
{
wlan_adapter *Adapter = priv->adapter;
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
struct sk_buff *skb;
u8 *cmdBuf;
int ret = 0;
ENTER();
if (Adapter->SurpriseRemoved)
return -1;
OS_INT_DISABLE;
if (((struct cf_card_rec *)(priv->wlan_dev.card))->do_get_int_work_around) {
u16 cause;
/* Read the reason code */
cause = inw(reg->card.int_cause) & CF_CCR_HIC_MASK;
if (!cause) {
PRINTK(" no interrupt\n");
goto sbi_get_int_status_exit;
}
PRINTK(" int_cause = 0x%02x @ %lu\n", cause, jiffies);
if (cause == 0xffff) {
Adapter->SurpriseRemoved = TRUE;
goto sbi_get_int_status_exit;
}
/* Write the reason code */
outw(cause, reg->card.int_cause);
if (cause & CF_CCR_HIC_TxDnLdRdy) {
priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
cf_int_cause |= HIS_TxDnLdRdy;
}
if (cause & CF_CCR_HIC_RxUpLdRdy)
cf_int_cause |= HIS_RxUpLdRdy;
#ifdef THROUGHPUT_TEST
else if (!Adapter->NumTransfersRx &&
Adapter->ThruputTest & 0x02)
cf_int_cause |= HIS_RxUpLdRdy;
#endif
if (cause & CF_CCR_HIC_CmdDnLdRdy)
cf_int_cause |= HIS_CmdDnLdRdy;
if (cause & CF_CCR_HIC_CmdRspRdy)
cf_int_cause |= HIS_CmdUpLdRdy;
if (cause & CF_CCR_HIC_CardEvent)
cf_int_cause |= HIS_CardEvent;
}
sbi_get_int_status_exit:
if (cf_int_cause & HIS_RxUpLdRdy) {
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
printk(KERN_ERR "No free skb\n");
priv->stats.rx_dropped++;
cf_int_cause &= ~HIS_RxUpLdRdy;
goto restore_int;
}
/* skb->tail is passed as we are calling skb_put after
* we are reading the data */
if (sbi_card_to_host(priv, MVMS_DAT,
&priv->wlan_dev.upld_len,
skb->tail, WLAN_UPLD_SIZE) < 0) {
PRINTK1("ERROR: Data Transfer from device"
" failed\n");
cf_int_cause &= ~HIS_RxUpLdRdy;
kfree_skb(skb);
goto restore_int;
}
skb_put(skb, priv->wlan_dev.upld_len);
list_add_tail((struct list_head *) skb,
(struct list_head *) &Adapter->RxSkbQ);
}
if (cf_int_cause & HIS_CmdUpLdRdy) {
if (!Adapter->CurCmd) {
cmdBuf = priv->wlan_dev.upld_buf;
cf_int_cause &= ~HIS_CmdUpLdRdy;
} else {
cmdBuf = Adapter->CurCmd->BufVirtualAddr;
}
/* SDCF: Move this into ProcessRxedPacket */
if (sbi_card_to_host(priv, MVMS_CMD,
&priv->wlan_dev.upld_len,
cmdBuf, WLAN_UPLD_SIZE) < 0) {
PRINTK1("ERROR: Data Transfer from device"
" failed\n");
goto restore_int;
}
}
if (cf_int_cause & HIS_TxDnLdRdy)
priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
restore_int:
*ireg = cf_int_cause;
cf_int_cause = 0;
OS_INT_RESTORE;
sbi_enable_host_int(priv, HIM_ENABLE);
PRINTK(" cf_int_cause = 0x%x\n", *ireg);
PRINTK(" adapter->HisRegCpy = 0x%x\n", Adapter->HisRegCpy);
LEAVE();
return ret;
}
int sbi_poll_cmd_dnld_rdy(wlan_private * priv)
{
return cf_IsCmdReady(priv);
}
int sbi_card_to_host(wlan_private *priv, u32 type, u32 *nb, u8 *payload,
u16 npayload)
{
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
ENTER();
if ((!payload) || (!npayload))
return -EINVAL;
if (type == MVMS_DAT) {
u16 len = inw(reg->card.io_data_len);
if (len <= 30 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
PRINTK(" invalid length %d - discarding\n", len);
priv->stats.rx_dropped++;
cf_RxEndPacket(priv);
return -1;
}
*nb = len;
insw(reg->host.io_data_read, (u16 *)payload, len / sizeof(u16));
if (len & 0x0001)
payload[len - 1] = inb(reg->host.io_data_read);
cf_UshortRegSetBits(priv, CF_HCR_HOST_STATUS, CF_HCR_HS_RxUpLdOvr);
cf_UshortRegSetBits(priv, CF_HCR_CARD_INT_CAUSE, CF_HCR_CIC_RxUpLdOvr);
} else if (type == MVMS_CMD) {
u16 len;
if (cf_IsRespReady(priv)) {
PRINTK(" device not ready\n");
LEAVE();
return -1;
}
len = inw(reg->card.io_cmd_read_len);
*nb = len;
if ((len == 0) || (len > MRVDRV_SIZE_OF_CMD_BUFFER)) {
PRINTK(" invalid length!\n");
return -1;
}
insw(reg->host.io_cmd_read, (u16 *)payload, len / sizeof(u16));
if (len & 0x0001)
payload[len - 1] = inb(reg->host.io_cmd_read);
PRINTK(" received %d bytes\n", len);
}
LEAVE();
return 0;
}
int sbi_read_event_cause(wlan_private * priv)
{
cfreg *reg = (cfreg *)priv->wlan_dev.ioport;
ENTER();
u16 usCardStatus;
usCardStatus = inw(reg->card.status);
usCardStatus &= CF_CCR_CS_STATUS_MASK;
usCardStatus = usCardStatus >> 5;
priv->adapter->EventCause = usCardStatus;
LEAVE();
return 0;
}
int sbi_retrigger(wlan_private * priv)
{
return 0;
}
int sbi_is_tx_download_ready(wlan_private * priv)
{
return cf_IsTxDownloadReady(priv);
}
int sbi_reenable_host_interrupt(wlan_private * priv, u8 bits)
{
u8 tmp = bits;
tmp &= CF_HCR_HIM_MASK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -