首页 DM9000网卡驱动分析

DM9000网卡驱动分析

举报
开通vip

DM9000网卡驱动分析DM9000网卡驱动分析 DM9000网卡驱动分析 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_ARCH_S3C2410) #include #endif #include "dm90...

DM9000网卡驱动分析
DM9000网卡驱动分析 DM9000网卡驱动分析 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_ARCH_S3C2410) #include #endif #include "dm9000.h" /* Board/System/Debug information/definition ---------------- */ //在EEPROM或PHY地址寄存器中要选择内部PHY,那么7-6位强制为01 #define DM9000_PHY  0x40 /* PHY address 0x01 */ #define CARDNAME "dm9000" #define DRV_VERSION "1.31" /*  * Transmit timeout, default 5 seconds.  */  //传输超时时间设定,当传输超时时调用函数dm9000_timeout(struct net_device *dev) static int watchdog = 5000; module_param(watchdog, int, 0400);//在驱动程序加载时可以重新设定watchdog MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); /* DM9000 register address locking.  *  * The DM9000 uses an address register to control where data written  * to the data register goes. This means that the address register  * must be preserved over interrupts or similar calls.  *  * During interrupt and other critical calls, a spinlock is used to  * protect the system, but the calls themselves save the address  * in the address register in case they are interrupting another  * access to the device.  *  * For general accesses a lock is provided so that calls which are  * allowed to sleep are serialised so that the address register does  * not need to be saved. This lock also serves to serialise access  * to the EEPROM and PHY access registers which are shared between  * these two devices.  */ /* The driver supports the original DM9000E, and now the two newer  * devices, DM9000A and DM9000B.  */ enum dm9000_type {  TYPE_DM9000E, /* original DM9000 */  TYPE_DM9000A,  TYPE_DM9000B }; /* Structure/enum declaration ------------------------------- */ typedef struct board_info { //cmd脚决定了数据数据口还是地址索引  void __iomem *io_addr; /* Register I/O base address */  void __iomem *io_data; /* Data I/O address */  u16   irq;  /* IRQ */  u16  tx_pkt_cnt;//当前待传输的数据包的数量,最多两个  //第二个数据包长度存于此处,第二个数据包写入网卡SRAM中后要释放skb  u16  queue_pkt_len;  u16  queue_start_addr;  u16  dbug_cnt;  u8  io_mode;  /* 0:word, 2:byte */  u8  phy_addr;  u8  imr_all; //在probe()函数中有db->flags = pdata->flags;  unsigned int flags;  unsigned int in_suspend :1;  int  debug_level;  enum dm9000_type type;  void (*inblk)(void __iomem *port, void *data, int length);  void (*outblk)(void __iomem *port, void *data, int length);  void (*dumpblk)(void __iomem *port, int length);  struct device *dev;      /* parent device */  struct resource *addr_res;   /* resources found */  struct resource *data_res;//物理地址  struct resource *addr_req;   /* resources requested */  struct resource *data_req;//I/O映射后的虚拟地址  struct resource *irq_res;  struct mutex  addr_lock; /* phy and eeprom access lock */ //在probe函数中初始化,处理函数dm9000_poll_work,链路连接状态改变  struct delayed_work phy_poll;  struct net_device  *ndev;  spinlock_t lock;  struct mii_if_info mii;  u32  msg_enable;//网络入口信息 } board_info_t; /* debug code */ #define dm9000_dbg(db, lev, msg...) do {  \  if ((lev) < CONFIG_DM9000_DEBUGLEVEL &&  \      (lev) < db->debug_level) {   \   dev_dbg(db->dev, msg);   \  }      \ } while (0) static inline board_info_t *to_dm9000_board(struct net_device *dev) {//存取私有数据指针专用函数  return  netdev_priv(dev); } /* DM9000 network board routine ---------------------------- */ static void dm9000_reset(board_info_t * db) {  dev_dbg(db->dev, "resetting device\n"); //NCR(00H):网络控制寄存器  /* RESET device */  writeb(DM9000_NCR, db->io_addr);  udelay(200);  writeb(NCR_RST, db->io_data);  udelay(200); } /*  *   Read a byte from I/O port  */ static u8 ior(board_info_t * db, int reg) {//对网卡寄存器进行操作要先写该寄存器的偏移地址  writeb(reg, db->io_addr);  return readb(db->io_data); } /*  *   Write a byte to I/O port  */ static void iow(board_info_t * db, int reg, int value) {  writeb(reg, db->io_addr);  writeb(value, db->io_data); } /* routines for sending block to chip */ static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) {  writesb(reg, data, count); } static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) {  writesw(reg, data, (count+1) >> 1); } static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) {  writesl(reg, data, (count+3) >> 2); } /* input block from chip to memory */ static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count) {  readsb(reg, data, count); } static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count) {  readsw(reg, data, (count+1) >> 1); } static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count) {  readsl(reg, data, (count+3) >> 2); } /* dump block from chip to null */ //读出没用的数据,为了改变网卡SRAM FIFO的数据指针, static void dm9000_dumpblk_8bit(void __iomem *reg, int count) {  int i;  int tmp;  for (i = 0; i < count; i++)   tmp = readb(reg); } static void dm9000_dumpblk_16bit(void __iomem *reg, int count) {  int i;  int tmp;  count = (count + 1) >> 1;  for (i = 0; i < count; i++)   tmp = readw(reg); } static void dm9000_dumpblk_32bit(void __iomem *reg, int count) {  int i;  int tmp;  count = (count + 3) >> 2;  for (i = 0; i < count; i++)   tmp = readl(reg); } /* dm9000_set_io  *  * select the specified set of io routines to use with the  * device  */ //设定I/O线宽 static void dm9000_set_io(struct board_info *db, int byte_width) {  /* use the size of the data resource to work out what IO   * routines we want to use   */  switch (byte_width) {  case 1:   db->dumpblk = dm9000_dumpblk_8bit;   db->outblk  = dm9000_outblk_8bit;   db->inblk   = dm9000_inblk_8bit;   break;  case 3:   dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n");  case 2:   db->dumpblk = dm9000_dumpblk_16bit;   db->outblk  = dm9000_outblk_16bit;   db->inblk   = dm9000_inblk_16bit;   break;  case 4:  default:   db->dumpblk = dm9000_dumpblk_32bit;   db->outblk  = dm9000_outblk_32bit;   db->inblk   = dm9000_inblk_32bit;   break;  } } /* 延时调度。用于 检测 工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训 网卡连接状态。 在open函数中调用。 TYPE_DM9000E在链路状态改变时是不产生中断的。 */ static void dm9000_schedule_poll(board_info_t *db) {  if (db->type == TYPE_DM9000E)   schedule_delayed_work(&db->phy_poll, HZ * 2); } static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) {  board_info_t *dm = to_dm9000_board(dev);  if (!netif_running(dev))   return -EINVAL;  return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); } static unsigned int dm9000_read_locked(board_info_t *db, int reg) {  unsigned long flags;  unsigned int ret;  spin_lock_irqsave(&db->lock, flags);  ret = ior(db, reg);  spin_unlock_irqrestore(&db->lock, flags);  return ret; } static int dm9000_wait_eeprom(board_info_t *db) {  unsigned int status;  int timeout = 8; /* wait max 8msec */  /* The DM9000 data sheets say we should be able to   * poll the ERRE bit in EPCR to wait for the EEPROM   * operation. From testing several chips, this bit   * does not seem to work.   *   * We attempt to use the bit, but fall back to the   * timeout (which is why we do not return an error   * on expiry) to say that the EEPROM operation has   * completed.   */  while (1) {   status = dm9000_read_locked(db, DM9000_EPCR); //EPCR/PHY_CR(0BH):EEPROM和PHY控制寄存器, //0:ERRE:EEPROM或PHY的访问状态。1表示EEPROM或PHY正在被访问   if ((status & EPCR_ERRE) == 0)    break;   msleep(1);   if (timeout-- < 0) {    dev_dbg(db->dev, "timeout waiting EEPROM\n");    break;   }  }  return 0; } /*  *  Read a word data from EEPROM  */ static void dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) {  unsigned long flags;  if (db->flags & DM9000_PLATF_NO_EEPROM) {   to[0] = 0xff;   to[1] = 0xff;   return;  }  mutex_lock(&db->addr_lock);  spin_lock_irqsave(&db->lock, flags); /* EPAR/PHY_AR(0CH):EEPROM或PHY地址寄存器 5-0:EROA:EEPROM字地址或PHY寄存器地址。 EPCR/PHY_CR(0BH):EEPROM和PHY控制寄存器。 对EEPROM的读写:写入寄存器DM9000_EPAR的偏移地址 ;写入要读写的EEPROM存储空间的地址到DM9000_EPAR; 配置EPCR,选择EEPROM和PHY,置读写位; 等待读写完成;到EPDRL和EPDRH中取数据。 */  iow(db, DM9000_EPAR, offset);  iow(db, DM9000_EPCR, EPCR_ERPRR);  spin_unlock_irqrestore(&db->lock, flags);  dm9000_wait_eeprom(db);  /* delay for at-least 150uS */  msleep(1);  spin_lock_irqsave(&db->lock, flags);  iow(db, DM9000_EPCR, 0x0);  to[0] = ior(db, DM9000_EPDRL);  to[1] = ior(db, DM9000_EPDRH);  spin_unlock_irqrestore(&db->lock, flags);  mutex_unlock(&db->addr_lock); } /*  * Write a word data to SROM  */ static void dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) {  unsigned long flags;  if (db->flags & DM9000_PLATF_NO_EEPROM)   return;  mutex_lock(&db->addr_lock);  spin_lock_irqsave(&db->lock, flags);  iow(db, DM9000_EPAR, offset);  iow(db, DM9000_EPDRH, data[1]);  iow(db, DM9000_EPDRL, data[0]);  iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);  spin_unlock_irqrestore(&db->lock, flags);  dm9000_wait_eeprom(db);  mdelay(1); /* wait at least 150uS to clear */  spin_lock_irqsave(&db->lock, flags);  iow(db, DM9000_EPCR, 0);  spin_unlock_irqrestore(&db->lock, flags);  mutex_unlock(&db->addr_lock); } /* ethtool ops */ //获取驱动信息 static void dm9000_get_drvinfo(struct net_device *dev,           struct ethtool_drvinfo *info) {  board_info_t *dm = to_dm9000_board(dev);  strcpy(info->driver, CARDNAME);  strcpy(info->version, DRV_VERSION);  strcpy(info->bus_info, to_platform_device(dm->dev)->name); } //获取网络接口信息 static u32 dm9000_get_msglevel(struct net_device *dev) {  board_info_t *dm = to_dm9000_board(dev);  return dm->msg_enable; } //设定网络接口信息 static void dm9000_set_msglevel(struct net_device *dev, u32 value) {  board_info_t *dm = to_dm9000_board(dev);  dm->msg_enable = value; } /* 设备无关接口的设定与信息获取最终是通过调用函数 dm9000_phy_read和dm9000_phy_write来实现的。 即是对PHY寄存器的读写。 */ static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {  board_info_t *dm = to_dm9000_board(dev);  mii_ethtool_gset(&dm->mii, cmd);  return 0; } static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) {  board_info_t *dm = to_dm9000_board(dev);  return mii_ethtool_sset(&dm->mii, cmd); } static int dm9000_nway_reset(struct net_device *dev) {  board_info_t *dm = to_dm9000_board(dev);  return mii_nway_restart(&dm->mii); } //NSR (01H):网络状态寄存器,获取网络连接状态信息 static u32 dm9000_get_link(struct net_device *dev) {  board_info_t *dm = to_dm9000_board(dev);  u32 ret;  if (dm->flags & DM9000_PLATF_EXT_PHY)   ret = mii_link_ok(&dm->mii);  else   ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0;  return ret; } #define DM_EEPROM_MAGIC  (0x444D394B) /* EPAR/PHY_AR(0CH):EEPROM或PHY地址寄存器, 5-0:EROA:EEPROM字地址或PHY寄存器地址。  2^6=128 */ static int dm9000_get_eeprom_len(struct net_device *dev) {  return 128; } //读取eeprom存储空间的值 static int dm9000_get_eeprom(struct net_device *dev,         struct ethtool_eeprom *ee, u8 *data) {  board_info_t *dm = to_dm9000_board(dev);  int offset = ee->offset;  int len = ee->len;  int i;  /* EEPROM access is aligned to two bytes */  if ((len & 1) != 0 || (offset & 1) != 0)   return -EINVAL;  if (dm->flags & DM9000_PLATF_NO_EEPROM)   return -ENOENT;  ee->magic = DM_EEPROM_MAGIC;  for (i = 0; i < len; i += 2)   dm9000_read_eeprom(dm, (offset + i) / 2, data + i);  return 0; } //向eeprom存储空间写入数据 static int dm9000_set_eeprom(struct net_device *dev,         struct ethtool_eeprom *ee, u8 *data) {  board_info_t *dm = to_dm9000_board(dev);  int offset = ee->offset;  int len = ee->len;  int i;  /* EEPROM access is aligned to two bytes */  if ((len & 1) != 0 || (offset & 1) != 0)   return -EINVAL;  if (dm->flags & DM9000_PLATF_NO_EEPROM)   return -ENOENT;  if (ee->magic != DM_EEPROM_MAGIC)   return -EINVAL;  for (i = 0; i < len; i += 2)   dm9000_write_eeprom(dm, (offset + i) / 2, data + i);  return 0; } /* ethtool 是一个实用工具, 设计来给系统管理员以大量的控制网络接口的操作.  用 ethtool, 可能来控制各种接口 参数 转速和进给参数表a氧化沟运行参数高温蒸汽处理医疗废物pid参数自整定算法口腔医院集中消毒供应 , 包括速度, 介质类型, 双工模式,   DMA 环设置, 硬件校验和, LAN 唤醒操作, 等等 */ static const struct ethtool_ops dm9000_ethtool_ops = {  .get_drvinfo  = dm9000_get_drvinfo,  .get_settings  = dm9000_get_settings,  .set_settings  = dm9000_set_settings,  .get_msglevel  = dm9000_get_msglevel,  .set_msglevel  = dm9000_set_msglevel,  .nway_reset  = dm9000_nway_reset,  .get_link  = dm9000_get_link,   .get_eeprom_len  = dm9000_get_eeprom_len,   .get_eeprom  = dm9000_get_eeprom,   .set_eeprom  = dm9000_set_eeprom, }; /* NCR (00H):网络控制寄存器 */ static void dm9000_show_carrier(board_info_t *db,     unsigned carrier, unsigned nsr) {  struct net_device *ndev = db->ndev;  unsigned ncr = dm9000_read_locked(db, DM9000_NCR);  if (carrier)   dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n",     ndev->name, (nsr & NSR_SPEED) ? 10 : 100,     (ncr & NCR_FDX) ? "full" : "half");  else   dev_info(db->dev, "%s: link down\n", ndev->name); } /* 工作队列struct delayed_work phy_poll;的处理函数。 检测网络连接状态,通知内核,载波丢失和载波回来。 */ static void dm9000_poll_work(struct work_struct *w) {  struct delayed_work *dw = to_delayed_work(w);  board_info_t *db = container_of(dw, board_info_t, phy_poll);  struct net_device *ndev = db->ndev;  if (db->flags & DM9000_PLATF_SIMPLE_PHY &&      !(db->flags & DM9000_PLATF_EXT_PHY)) {   unsigned nsr = dm9000_read_locked(db, DM9000_NSR);   unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;   unsigned new_carrier;   new_carrier = (nsr & NSR_LINKST) ? 1 : 0;   if (old_carrier != new_carrier) {    if (netif_msg_link(db))     dm9000_show_carrier(db, new_carrier, nsr);    if (!new_carrier)     netif_carrier_off(ndev);    else     netif_carrier_on(ndev);   }  } else   mii_check_media(&db->mii, netif_msg_link(db), 0);    if (netif_running(ndev))   dm9000_schedule_poll(db);//如果没连接上会一直检测。 } /* dm9000_release_board  *  * release a board, and any mapped resources  */ static void dm9000_release_board(struct platform_device *pdev, struct board_info *db) {  /* unmap our resources */  iounmap(db->io_addr);  iounmap(db->io_data);//释放映射的I/O地址空间  /* release the resources */  release_resource(db->data_req);  kfree(db->data_req);  release_resource(db->addr_req);  kfree(db->addr_req); } static unsigned char dm9000_type_to_char(enum dm9000_type type) {  switch (type) {  case TYPE_DM9000E: return 'e';  case TYPE_DM9000A: return 'a';  case TYPE_DM9000B: return 'b';  }  return '?'; } /*  *  Set DM9000 multicast address  */  /*  在probe函数中有ndev->set_multicast_list = &dm9000_hash_table  当设备的组播列表改变和当标志改变时调用该函数。    一个组播报文是一个会被多个主机接收的网络报文, 但不是所有主机.   这个功能通过给一组主机分配特殊的硬件地址来获得. 发向一个特殊   地址的报文应当被那个组当中的所有主机接收.      内核来跟踪在任何给定时间对哪些组播地址感兴趣. 这个列表可能经常改变,    因为它是在任何给定时间和按照用户意愿运行的应用程序的功能.     驱动的工作是接收感兴趣的组播地址列表并递交给内核任何发向这些地址    的报文.        MAR(16H -- 1DH):多点发送地址寄存器  */ static void dm9000_hash_table(struct net_device *dev) {  board_info_t *db = netdev_priv(dev);  struct dev_mc_list *mcptr = dev->mc_list;  int mc_cnt = dev->mc_count;  int i, oft;  u32 hash_val;  u16 hash_table[4];  u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;  unsigned long flags;  dm9000_dbg(db, 1, "entering %s\n", __func__);  spin_lock_irqsave(&db->lock, flags);  for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)   iow(db, oft, dev->dev_addr[i]);  /* Clear Hash Table */  for (i = 0; i < 4; i++)   hash_table[i] = 0x0;  /* broadcast address */  hash_table[3] = 0x8000;  if (dev->flags & IFF_PROMISC)   rcr |= RCR_PRMSC;  if (dev->flags & IFF_ALLMULTI)   rcr |= RCR_ALL;  /* the multicast address in Hash Table : 64 bits */  for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {   hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;   hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);  } //MAR(16H -- 1DH):多点发送地址寄存器(Multicast Address Register )   /* Write the hash table to MAC MD table */  for (i = 0, oft = DM9000_MAR; i < 4; i++) {   iow(db, oft++, hash_table[i]);   iow(db, oft++, hash_table[i] >> 8);  }  iow(db, DM9000_RCR, rcr);  spin_unlock_irqrestore(&db->lock, flags); } /*  * Initilize dm9000 board  */ static void dm9000_init_dm9000(struct net_device *dev) {  board_info_t *db = netdev_priv(dev);  unsigned int imr;  dm9000_dbg(db, 1, "entering %s\n", __func__); /* ISR(FEH):终端状态寄存器(Interrupt Status Register)    7-6:IOMODE:处理器模式。00为16位模式,01为32位模式, 10为8位模式,00保留。 */  /* I/O mode */  db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* GPR(1FH):GPIO寄存器, GPCR(1FH):GPIO控制寄存器, GPIO0默认为输出做POWER_DOWN功能。其它默认为输入. */  /* GPIO0 on pre-activate PHY */  iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */  iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */  /*  GPCR的第0位0:GEPIO0:该位默认为输出1到POWER_DEWN内部PHY。  若希望启用PHY,则驱动程序需要通过写“0”将PWER_DOWN信号清零。  */  iow(db, DM9000_GPR, 0); /* Enable PHY */  if (db->flags & DM9000_PLATF_EXT_PHY)   iow(db, DM9000_NCR, NCR_EXT_PHY); /* TCR(02H):发送控制寄存器; BPTR(08H):背压门限寄存器; FCR(0AH):接收/发送溢出控制寄存器; SMCR(2FH):特殊模式控制寄存器; */  /* Program operating register */  iow(db, DM9000_TCR, 0);         /* TX Polling clear */  /* 内部存储器空间大少 16K 字节。低 3K 字节单元用作发送包的缓冲区, 其他 13K 字节用作接收包的缓冲区。所以在写发送包存储区的时候, 当存储器地址越界后,自动跳回 0 地址并置位 IMR 第七位。同样 在读接收包存储器的时候,当存储器地址越界后,自动跳回起始地址 0x0c00。   */  iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */  iow(db, DM9000_FCR, 0xff); /* Flow Control */  iow(db, DM9000_SMCR, 0);        /* Special Mode */  /* clear TX status */  iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);  iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */  /* Set address filter table */  //设置地址过滤表,即组播地址  dm9000_hash_table(dev); /* IMR(FFH):终端屏蔽寄存器. 7:PAR:1使能指针自动跳回。 1:PTI:1使能数据包传输终端。 0:PRI:1使能数据包接收中断。 5:LNKCHGI:1使能连接状态改变中断。 DM9000E没有连接状态改变中断。 */  imr = IMR_PAR | IMR_PTM | IMR_PRM;  if (db->type != TYPE_DM9000E)   imr |= IMR_LNKCHNG;  db->imr_all = imr;  /* Enable TX/RX interrupt mask */  iow(db, DM9000_IMR, imr);  /* Init Driver variable */  db->tx_pkt_cnt = 0;  db->queue_pkt_len = 0;  dev->trans_start = 0; } /* Our watchdog timed out. Called by the networking layer */ //传输超时时调用该函数,超时时间由watchdog设定。 static void dm9000_timeout(struct net_device *dev) {  board_info_t *db = netdev_priv(dev);  u8 reg_save;  unsigned long flags;  /* Save previous register address */  reg_save = readb(db->io_addr);//不理解  spin_lock_irqsave(&db->lock, flags); /* 驱动需要告知网络系统不要再启动发送直到硬件准备好接收新的数据. 这个通知通过调用 netif_stop_queue 来实现。 */  netif_stop_queue(dev);  dm9000_reset(db);  dm9000_init_dm9000(dev);  /* We can accept TX packets again */  /*  如果当前系统时间超过设备的 trans_start 时间至少 一个超时周期值,   网络层最终调用驱动的 tx_timeout 方法.  */  dev->trans_start = jiffies;  netif_wake_queue(dev);  /* Restore previous register address */  writeb(reg_save, db->io_addr);  spin_unlock_irqrestore(&db->lock, flags); } /*  *  Hardware start transmission.  *  Send a packet to media from the upper layer.  */  /*   从上层向硬件发送数据包,最终调用此函数  */ static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) {  unsigned long flags;  board_info_t *db = netdev_priv(dev);  dm9000_dbg(db, 3, "%s:\n", __func__); //一次最多只能发送两个数据包。即网卡SRAM中只能存在两个待发送的数据包。  if (db->tx_pkt_cnt > 1)   return 1;  spin_lock_irqsave(&db->lock, flags);  /* Move data to DM9000 TX RAM */  /*  MWCMD(F8H):存储器读地址自动增加的读数据命令.  7-0:MWCMD:写数据到发送SRAM中,之后指向内部SRAM的读指针自动  增加1、2或4,根据处理器的操作模式而定(8位、16位或32位)。   */  writeb(DM9000_MWCMD, db->io_addr);  (db->outblk)(db->io_data, skb->data, skb->len);  dev->stats.tx_bytes += skb->len;  db->tx_pkt_cnt++;//记录写入网卡SRAM中待发送的数据包的数量  /* TX control: First packet immediately send, second packet queue */  if (db->tx_pkt_cnt == 1) {   /* Set TX length to DM9000 */   iow(db, DM9000_TXPLL, skb->len);   iow(db, DM9000_TXPLH, skb->len >> 8); //如果写入网卡SRAM中的数据包只有一个,则将数据包的长度写入TXPLL和TXPLH中   /* Issue TX polling command */ //TCR(02H):发送控制寄存器。0:TXREQ:TX(发送)请求。发送完成后自动清零该位。   iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ //保存当前jiffies值   dev->trans_start = jiffies; /* save the time stamp */  } else {   /* Second packet */ //如果当前写入的数据包不是的一个,则把该数据包的长度存入db->queue_pkt_len中   db->queue_pkt_len = skb->len; //只能同时存在两个待发数据包。调用函数告知网络系统不要再启动发送   netif_stop_queue(dev);  }  spin_unlock_irqrestore(&db->lock, flags);  /* free this SKB */ /* 每个数据包写入网卡SRAM后都要释放skb。 如果有两个数据包要将第二个数据包的长度存入db->queue_pkt_len = skb->len */  dev_kfree_skb(skb);  return 0; } /*  * DM9000 interrupt handler  *
本文档为【DM9000网卡驱动分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_239344
暂无简介~
格式:doc
大小:138KB
软件:Word
页数:39
分类:互联网
上传时间:2011-08-17
浏览量:26