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

📄 if_cf.c

📁 marvell cf wifi driver source code CF-8385-linux-x86-5.0.4.p0-132-src.rar
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
  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 + -