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

📄 dev_net_cs8900a.c

📁 嵌入式的开发的一个开源仿真程序源码,其是开源的,很不错的奉献给大家
💻 C
字号:
//zzc: 2005-2-6 currently not support network simulation on Cygwin
#ifndef __CYGWIN__
/*
	dev_net_cs8900a.c - skyeye Cirrus Logic CS8900A ethernet controllor simulation
	Copyright (C) 2003 - 2005 Skyeye Develop Group
        for help please send mail to <skyeye-developer@lists.gro.clinux.org>
	
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
*/
/*
 * 06/04/2005   initial verion for cs8900a
 *                      walimis <wlm@student.dlut.edu.cn>
 */

#include <signal.h>
#include <sys/time.h>
#include <armdefs.h>
#include "skyeye_device.h"
#include "dev_net_cs8900a.h"

static struct device_default_value cs8900a_net_def[] = {
  /* name         base        size   interrupt array */
  {"at91", 0xfffa0000, 0x20, {16, 0, 0, 0}},
  {"s3c2410x", 0x19000300, 0x20, {9, 0, 0, 0}},
  {NULL},
};

#define MAX_DEVICE_NUM 10
static struct device_desc *cs8900a_devs[MAX_DEVICE_NUM];


void
net_cs8900a_set_update_intr (struct device_desc *dev)
{
  struct device_interrupt *intr = &dev->intr;
  struct machine_config *mc = (struct machine_config *) dev->mach;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  mc->mach_set_intr (intr->interrupts[INT_CS8900A]);
  mc->mach_update_intr (mc);
}

inline void
set_time (int packets)
{
  struct itimerval value;
  value.it_value.tv_sec = 0;
  value.it_value.tv_usec = packets;
  value.it_interval = value.it_value;
  setitimer (ITIMER_REAL, &value, NULL);
}

static void
send_interrupt ()
{
  int i;
  struct device_desc *dev;

  for (i = 0; i < MAX_DEVICE_NUM; i++)
    {
      if ((dev = cs8900a_devs[i]) != NULL)
	{
	  struct net_device *net_dev = (struct net_device *) dev->dev;
	  struct machine_config *mc = (struct machine_config *) dev->mach;
	  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
	  if ((io->need_update))
	    {
	      /* only update once. */
	      net_cs8900a_set_update_intr (dev);
	      io->need_update = 0;
	      set_time (0);
	      return;
	    }

	}
    }
}
static void
init_sigaction (void)
{
  struct sigaction act;
  act.sa_handler = send_interrupt;
  act.sa_flags = 0;
  sigemptyset (&act.sa_mask);
  sigaction (SIGALRM, &act, NULL);
}


/* ISQ read*/
static void
isq_read (struct device_desc *dev, u16 * data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  io->ctrl_st[CtrlStNum (PP_ISQ)] = 0x0;
  if (io->ctrl_st[CtrlStNum (PP_RxEvent)] & 0xffc0)
    {
      io->ctrl_st[CtrlStNum (PP_ISQ)] = io->ctrl_st[CtrlStNum (PP_RxEvent)];
      io->ctrl_st[CtrlStNum (PP_RxEvent)] &= 0x3f;
    }
  else if (io->ctrl_st[CtrlStNum (PP_TxEvent)] & 0xffc0)
    {
      io->ctrl_st[CtrlStNum (PP_ISQ)] = io->ctrl_st[CtrlStNum (PP_TxEvent)];
      io->ctrl_st[CtrlStNum (PP_TxEvent)] &= 0x3f;
    }

  *data = io->ctrl_st[CtrlStNum (PP_ISQ)];
}

static void
frame_write (struct device_desc *dev, u16 data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  io->tx_frame[io->tx_tail] = data;
  io->tx_tail++;
  if ((io->tx_tail * 2) >= io->tx_length)
    {
      cs8900a_output (dev, (u8 *) io->tx_frame, (io->tx_tail * 2));
      io->tx_tail = 0;
    }
}

static void
frame_read (struct device_desc *dev, u16 * data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  if (io->rx_tail > io->rx_head)
    {
      io->rx_head = io->rx_tail = 0;
      return;
    }
  *data = io->rx_frame[io->rx_tail];
  io->rx_tail++;
}


static void
eeprom_reset (struct device_desc *dev)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  u8 offset, checksum = 0, *buf;

  u16 eeprom_val[17] = { 0xa120,
    0x2020, 0x0300, 0x0003, 0x0001,
    0x502c, 0xe000, 0x000f, 0x0, 0xd, 0xc000, 0xf,
    0x2158, 0x0010, 0x0, 0x0,
    0x2800
  };

  /* set eeprom mac address */
  eeprom_val[13] = net_dev->macaddr[0] | (net_dev->macaddr[1] << 8);
  eeprom_val[14] = net_dev->macaddr[2] | (net_dev->macaddr[3] << 8);
  eeprom_val[15] = net_dev->macaddr[4] | (net_dev->macaddr[5] << 8);

  /* re-compute checksum. */
  buf = (u8 *) eeprom_val;
  for (offset = 0; offset < (sizeof (eeprom_val) - 2); offset++)
    checksum += buf[offset];
  eeprom_val[16] = ((u8) (0x100 - checksum)) << 8;

  /* fill eeprom. */
  memcpy (io->eeprom, eeprom_val, sizeof (eeprom_val));

  /* others */
  io->eeprom_writable = 0;

  io->ctrl_st[CtrlStNum (PP_SelfST)] |= EEPROMpresent | EEPROMOK;

  memcpy (io->ieee_addr, net_dev->macaddr, 6);

}

static void
ctrl_status_write (struct device_desc *dev, u16 data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  io->ctrl_st[CtrlStNum (io->pp_address)] = data;
  //printf("%s: addr %x, data %x\n", __FUNCTION__, io->pp_address, data);
}

static void
ctrl_status_read (struct device_desc *dev, u16 * data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  *data = io->ctrl_st[CtrlStNum (io->pp_address)];
  //printf("%s: addr %x, data %x\n", __FUNCTION__, io->pp_address, *data);
}

/* FIXME: now it doesn't support erase-all/write-all commands
 */
static void
eeprom_write (struct device_desc *dev, u16 data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  if ((io->eeprom_cmd & EEWriteRegister) && io->eeprom_writable == 1)
    {
      io->eeprom[io->eeprom_cmd & 0xff] = io->eeprom_data;
    }
  else if ((io->eeprom_cmd & EEEraseRegister) && io->eeprom_writable == 1)
    {
      io->eeprom[io->eeprom_cmd & 0xff] = 0xffff;
    }
  else
    {
      if (io->eeprom_cmd & EEWriteEnable)
	{
	  io->eeprom_writable = 1;
	}
      else if (io->eeprom_cmd & EEWriteDis)
	{
	  io->eeprom_writable = 0;
	}
    }

}
static void
eeprom_read (struct device_desc *dev, u16 * data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  if (!(io->eeprom_cmd & EEReadRegister))
    return;

  *data = io->eeprom[io->eeprom_cmd & 0xff];

}

static void
net_cs8900a_fini (struct device_desc *dev)
{
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  free (dev->dev);
  free (io);
}

static void
net_cs8900a_reset (struct device_desc *dev)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  int i;

  /* set ProductID: rev_d */
  io->product_id[0] = EISA_REG_CODE;
  io->product_id[1] = CS8900A | (REV_D << 8);

  /* see section 4.10.5 */
  io->pp_address |= 0x3000;


  /* set control and status registers low 6 bits. see P49. */
  for (i = 0; i < 16; i++)
    {
      io->ctrl_st[i] |= i * 2 + 1;
      io->ctrl_st[i + 16] |= i * 2;

    }
  io->ctrl_st[CtrlStNum (PP_BusST)] |= Rdy4TxNOW;

  eeprom_reset (dev);

  /* init tx/rx buffer */
  if (!io->rx_frame)
    io->rx_frame = (u16 *) malloc (Rx_Frame_Count);
  memset (io->rx_frame, 0, Rx_Frame_Count);
  io->rx_status_p = &(io->rx_frame[0]);
  io->rx_length_p = &(io->rx_frame[1]);
  io->rx_head = io->rx_tail = 0;

  if (!io->tx_frame)
    io->tx_frame = (u16 *) malloc (Tx_Frame_Count);
  memset (io->tx_frame, 0, Tx_Frame_Count);
  io->tx_head = io->tx_tail = 0;
}

static void
net_cs8900a_update (struct device_desc *dev)
{
  struct device_interrupt *intr = &dev->intr;
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  struct machine_config *mc = (struct machine_config *) dev->mach;
  if ((!mc->mach_pending_intr (intr->interrupts[INT_CS8900A])))
    {
      fd_set frds;
      struct timeval tv;
      int ret;
      FD_ZERO (&frds);
      FD_SET (net_dev->net_fd, &frds);
      tv.tv_sec = 0;
      tv.tv_usec = 0;
      if ((ret = select (net_dev->net_fd + 1, &frds, NULL, NULL, &tv)) > 0)
	{
	  if (FD_ISSET (net_dev->net_fd, &frds))
	    {
	      cs8900a_input (dev);
	    }
	}
    }

}


int
net_cs8900a_read_halfword (struct device_desc *dev, u32 addr, u16 * data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  int offset = (u16) (addr - dev->base);
  int ret = ADDR_HIT;

  *data = 0;
  switch (offset)
    {
    case Rx_Frame_Port:
      frame_read (dev, data);
      break;
    case IO_ISQ:
      isq_read (dev, data);
      break;
    case PP_Address:
      *data = io->pp_address | 0x3000;
      break;
    case PP_Data:
      if (io->pp_address >= 0x100 && io->pp_address < 0x140)
	{

	  ctrl_status_read (dev, data);
	}
      switch (io->pp_address)
	{
	case PP_ProductID:
	  *data = io->product_id[0];
	  break;
	case PP_ProductID + 2:
	  *data = io->product_id[1];
	  break;
	case PP_IntNum:
	  *data = io->int_num;
	  break;
	case PP_EEPROMCommand:
	  *data = io->eeprom_cmd;
	  break;
	case PP_EEPROMData:
	  eeprom_read (dev, data);
	  break;

	case PP_IA:
	case PP_IA + 2:
	case PP_IA + 4:
	  *data = io->ieee_addr[io->pp_address - PP_IA] |
	    (io->ieee_addr[io->pp_address - PP_IA + 1] << 8);
	  break;
	case PP_ISQ:
	  isq_read (dev, data);
	  break;

	case PP_RxStatus:
	  *data = *(io->rx_status_p);
	  *(io->rx_status_p) = 0;
	  io->rx_tail++;
	  break;
	case PP_RxLength:
	  *data = *(io->rx_length_p);
	  *(io->rx_length_p) = 0;
	  io->rx_tail++;
	  break;
	}
      //printf("addr:%x, data:%x\n", io->pp_address, *data);
      break;
    default:
      break;
    }
  return ret;

}

int
net_cs8900a_write_halfword (struct device_desc *dev, u32 addr, u16 data)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;

  int offset = (u16) (addr - dev->base);
  int ret = ADDR_HIT;

  switch (offset)
    {
    case Tx_Frame_Port:
      frame_write (dev, data);
      break;
    case IO_TxCMD:
      io->tx_cmd = data;
      break;
    case IO_TxLength:
      io->tx_length = data;
      break;
    case PP_Address:
      io->pp_address = data;
      break;
    case PP_Data:
      if (io->pp_address >= 0x100 && io->pp_address < 0x140)
	{

	  ctrl_status_write (dev, data);
	}
      switch (io->pp_address)
	{
	case PP_IntNum:
	  io->int_num = data;
	  break;
	case PP_EEPROMCommand:
	  io->eeprom_cmd = data;
	  eeprom_write (dev, data);
	  break;
	case PP_EEPROMData:
	  if (io->eeprom_writable == 1)
	    io->eeprom_data = data;
	  break;
	case PP_IA:
	case PP_IA + 2:
	case PP_IA + 4:
	  io->ieee_addr[io->pp_address - PP_IA] = data & 0xff;
	  io->ieee_addr[io->pp_address - PP_IA + 1] = (data >> 8) & 0xff;
	  break;
	case PP_TxCMD:
	  io->tx_cmd = data;
	  break;
	case PP_TxLength:
	  io->tx_length = data;
	  break;
	}
      break;
    default:
      break;
    }

  return ret;
}

static void
cs8900a_input (struct device_desc *dev)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  int packet_len, cs8900a_len;
  u8 *bufptr;

  bufptr = (u8 *) & (io->rx_frame[2]);
  packet_len = net_dev->net_read (net_dev, bufptr, Rx_Max_Count);
  if (packet_len < 0)
    return;

  *(io->rx_status_p) |= RxOK;
  *(io->rx_length_p) = packet_len;

  io->rx_head = 2;

  io->rx_head = io->rx_head + ((packet_len + 1) / 2) - 1;

  io->rx_tail = 0;

  //printf("io->rx_head:%d, io->rx_tail:%d, packet_len:%d\n", io->rx_head, io->rx_tail, packet_len);

#if 0
  print_packet (bufptr, packet_len);
#endif

  io->ctrl_st[CtrlStNum (PP_RxEvent)] |= 0x100;	//TxOK
  if (io->ctrl_st[CtrlStNum (PP_BusCTL)] & EnableRQ)
    {
      //printf("%s:%x, packet_len:%d\n", __FUNCTION__, io->ctrl_st[CtrlStNum(PP_RxEvent)], packet_len);
      set_time (packet_len);
      io->need_update = 1;
      net_cs8900a_set_update_intr (dev);
    }
}

static u8
cs8900a_output (struct device_desc *dev, u8 * buf, u16 packet_len)
{
  struct net_device *net_dev = (struct net_device *) dev->dev;
  struct net_cs8900a_io *io = (struct net_cs8900a_io *) dev->data;
  int len;

  //printf("%s: packet_len:%d\n", __FUNCTION__, packet_len);
#if 0
  print_packet (buf, packet_len);
#endif
  if ((len = net_dev->net_write (net_dev, buf, packet_len)) == -1)
    {
      fprintf (stderr, "write to tapif error in skyeye-ne2k.c\n");
      return -1;
    }
  io->ctrl_st[CtrlStNum (PP_TxEvent)] |= 0x100;
  io->ctrl_st[CtrlStNum (PP_BusST)] |= Rdy4TxNOW;

  if (io->ctrl_st[CtrlStNum (PP_BusCTL)] & EnableRQ)
    {
      set_time (packet_len);
      io->need_update = 1;
      net_cs8900a_set_update_intr (dev);
    }
  return 0;
}
static int
net_cs8900a_setup (struct device_desc *dev)
{
  int i;
  int enough = 0;
  struct net_cs8900a_io *io;
  struct device_interrupt *intr = &dev->intr;

  dev->fini = net_cs8900a_fini;
  dev->reset = net_cs8900a_reset;
  dev->update = net_cs8900a_update;
  dev->read_halfword = net_cs8900a_read_halfword;
  dev->write_halfword = net_cs8900a_write_halfword;

  io = (struct net_cs8900a_io *) malloc (sizeof (struct net_cs8900a_io));
  memset (io, 0, sizeof (struct net_cs8900a_io));
  if (io == NULL)
    return 1;
  dev->data = (void *) io;

  net_cs8900a_reset (dev);

  init_sigaction ();

  /* see if we need to set default values.
   * */
  set_device_default (dev, cs8900a_net_def);

  for (i = 0; i < MAX_DEVICE_NUM; i++)
    {
      if (cs8900a_devs[i] == NULL)
	{
	  cs8900a_devs[i] = dev;
	  enough = 1;
	  break;
	}
    }
  if (enough == 0)
    return 1;

  return 0;
}

void
net_cs8900a_init (struct device_module_set *mod_set)
{
  int i;
  register_device_module ("cs8900a", mod_set, &net_cs8900a_setup);

  for (i = 0; i < MAX_DEVICE_NUM; i++)
    cs8900a_devs[i] = NULL;

}

//zzc:#endif __CYGWIN__
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -