b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Bumble_Bee

电脑杂谈  发布时间:2020-03-19 21:14:26  来源:网络整理

驱动人生离线网卡xp版_驱动人生6网卡版_网卡驱动代码

I. 网卡驱动程序体系结构

从上至下: 应用程序→系统调用接口→与协议无关的接口→网络协议栈→与设备无关的接口→设备驱动程序.

第二个重要的数据结构

1. Linux内核中的每个网卡都由net_device结构描述.

2. 网卡操作功能集: net_device_ops,此数据结构是上述net_device的成员.

3. 网络数据包: sk_buff.

网卡驱动代码,网卡驱动程序代码分析

使用的文件是cs89x0.c,主要分析三个部分: 网卡初始化,发送数据,接收数据.

㈠网卡初始化

驱动人生离线网卡xp版_驱动人生6网卡版_网卡驱动代码

网卡驱动程序的初始化主要在函数init_module中完成,其中一些代码如下:

int __init init_module(void)
{
  struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
  struct net_local *lp;
  int ret = 0;
  ...
  dev->irq = irq;
  dev->base_addr = io;
  ...
  ret = cs89x0_probe1(dev, io, 1);
  ...
}

cs89x0_probe1函数的代码如下:

static int __init cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
{
  struct net_local *lp = netdev_priv(dev);
  static unsigned version_printed;
  int i;
  int tmp;
  unsigned rev_type = 0;
  int eeprom_buff[CHKSUM_LEN];
  int retval;
  ...
  writeword(ioaddr, ADD_PORT, PP_ChipID);
  tmp = readword(ioaddr, DATA_PORT);      //对硬件的初始化
  ...
  
  for (i = 0; i < ETH_ALEN/2; i++)       //初始化MAC地址
  {
    dev->dev_addr[i*2] = eeprom_buff[i];
    dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
  }
  ...
  
  dev->netdev_ops    = &net_ops;        //初始化netdev_ops
  ...
  retval = register_netdev(dev);        //注册网卡驱动
}

从代码中可以看到

1. 使用alloc_etherdev函数定义和分配net_device结构.

2. 初始化net_device. (包括中断号,I / O基地址,MAC地址,netdev_ops)

3. 初始化硬件

4. 将网卡驱动程序注册到内核,使用函数register_netdev

驱动人生6网卡版_驱动人生离线网卡xp版_网卡驱动代码

㈡发送数据

netdev_ops初始化为值&net_ops,并且可以在此结构中找到发送函数

static const struct net_device_ops net_ops = {
    .ndo_open        = net_open,
    .ndo_stop        = net_close,
    .ndo_tx_timeout        = net_timeout,
    .ndo_start_xmit     = net_send_packet,
    .ndo_get_stats        = net_get_stats,
    .ndo_set_multicast_list = set_multicast_list,
    .ndo_set_mac_address     = set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER
    .ndo_poll_controller    = net_poll_controller,
#endif
    .ndo_change_mtu        = eth_change_mtu,
    .ndo_validate_addr    = eth_validate_addr,
};

net_send_packet代码如下:

static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
{
    struct net_local *lp = netdev_priv(dev);
    unsigned long flags;
    if (net_debug > 3) {
        printk("%s: sent %d byte packet of type %x\n",
            dev->name, skb->len,
            (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
    }

spin_lock_irqsave(&lp->lock, flags); netif_stop_queue(dev); /* initiate a transmit sequence */ writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd); writeword(dev->base_addr, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { spin_unlock_irqrestore(&lp->lock, flags); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); spin_unlock_irqrestore(&lp->lock, flags); dev->stats.tx_bytes += skb->len; dev_kfree_skb (skb); return NETDEV_TX_OK; }

代码的这一部分执行这些操作(以红色突出显示)

1. 通知上层协议停止向网卡发送数据.

由于网卡现在正在发送数据包,因此停止接收数据包

2. 将skb中的数据写入寄存器并发送出去

网卡驱动代码_驱动人生离线网卡xp版_驱动人生6网卡版

3. 释放skb空间

但这还没有结束. 如果这是上层协议的结尾,并且您仍然无法将数据发送到网卡,则该网卡将无法正常工作. 显然网卡驱动代码,这是异常的. 那么上层协议又被允许在哪里将数据包发送到网卡呢?

实际上,当网卡发送数据包时,它将进入网卡中断程序,查找request_irq中断处理程序名称为net_interrupt

static irqreturn_t net_interrupt(int irq, void *dev_id)
{
  struct net_device *dev = dev_id;
  struct net_local *lp;
  int ioaddr, status;
  int handled = 0;

  ioaddr = dev->base_addr;
  lp = netdev_priv(dev);

  while ((status = readword(dev->base_addr, ISQ_PORT)))
  {
    switch(status & ISQ_EVENT_MASK)
    {
      ...
      case ISQ_TRANSMITTER_EVENT:
        dev->stats.tx_packets++;
        netif_wake_queue(dev);    /* Inform upper layers. */
        if ((status & (    TX_OK |
                    TX_LOST_CRS |
                    TX_SQE_ERROR |
                    TX_LATE_COL |
                    TX_16_COL)) != TX_OK) {
                if ((status & TX_OK) == 0)
                    dev->stats.tx_errors++;
                if (status & TX_LOST_CRS)
                    dev->stats.tx_carrier_errors++;
                if (status & TX_SQE_ERROR)
                    dev->stats.tx_heartbeat_errors++;
                if (status & TX_LATE_COL)
                    dev->stats.tx_window_errors++;
                if (status & TX_16_COL)
                    dev->stats.tx_aborted_errors++;
            }
            break;
      ...
    }  
  }
}

4. 通知上层协议将数据包发送到网卡. 使用功能netif_wake_queue

㈢数据接收

网卡收到数据包后,进入网卡中断处理程序

static irqreturn_t net_interrupt(int irq, void *dev_id)
{
  struct net_device *dev = dev_id;
  struct net_local *lp;
  int ioaddr, status;
  int handled = 0;
  ioaddr = dev->base_addr;
  lp = netdev_priv(dev);
  while ((status = readword(dev->base_addr, ISQ_PORT)))
  {
    switch(status & ISQ_EVENT_MASK) 
    {
      ...
      case ISQ_RECEIVER_EVENT:
        /* Got a packet(s). */
        net_rx(dev);
        break;
    }  
  }
}
 

net_rx功能代码如下

驱动人生离线网卡xp版_网卡驱动代码_驱动人生6网卡版

static void net_rx(struct net_device *dev)
{
    struct sk_buff *skb;
    int status, length;
    int ioaddr = dev->base_addr;
    status = readword(ioaddr, RX_FRAME_PORT);
    length = readword(ioaddr, RX_FRAME_PORT);
    if ((status & RX_OK) == 0) {
        count_rx_errors(status, dev);
        return;
    }
    /* Malloc up new buffer. */
    skb = dev_alloc_skb(length + 2);
    if (skb == NULL) {
#if 0        /* Again, this seems a cruel thing to do */
        printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
#endif
        dev->stats.rx_dropped++;
        return;
    }
    skb_reserve(skb, 2);    /* longword align L3 header */
    readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
    if (length & 1)
        skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT);
    if (net_debug > 3) {
        printk(    "%s: received %d byte packet of type %x\n",
            dev->name, length,
            (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
    }
        skb->protocol=eth_type_trans(skb,dev);
    netif_rx(skb);
    dev->stats.rx_packets++;
    dev->stats.rx_bytes += length;
}

从代码中可以看到:

1. 阅读接收状态

2,读取接收到的数据的长度

3. 分配skb结构,skb = dev_alloc_skb(长度+ 2);

4. 从硬件寄存器读取数据并将其存储在skb

5. 使用功能netif_rx

将江封装的数据包向上发送到协议栈

这里粗略分析网卡驱动程序体系结构. 如果您有任何疑问或错误,欢迎指出.


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-145262-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 廪辛
        廪辛

        竟然有五条优质高蛋白

      每日福利
      热点图片
      拼命载入中...