文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>ZT Linux-2.6.20的cs8900驱动分析(三)

ZT Linux-2.6.20的cs8900驱动分析(三)

时间:2010-09-14  来源:lee213

三、 net_rx 和 net_send_packet 3.1 net_rx 在这部分将介绍cs8900 驱动的两个最重要的函数,内核通过该两个函数实现了数据的收发。net_rx 函数的主要功能是从cs8900 的片上数据缓冲区中将数据传送给sk_buff 缓冲区,sk_buff 是网络驱动程序与Linux 内核通信的缓冲区。该结构可在<top_dir>\include\linux\skbuff.h 中找到。net_rx 函数的功能可总结如下:(该总结来源于:http://www.akae.cn/bbs/archiver/?tid-6657.html ) A .获取私有数据存放于lp 中; B .获取设备缓冲区状态和缓冲长度; C .如果状态不为RX_OK 则计数接收数据错误次数count_rx_error() D .分配一个sk_buf 区间 E .字对齐,skb_reserve() ; F .插入数据到接收口,insw() ; G .写入数据; H .初始化sk_buff 结构,eth_type_trans() I .进入上层接收函数netif_rx() ; J .初始化设备的计数; net_rx 函数的注解如下所示: static void net_rx(struct net_device *dev) {        struct net_local *lp = netdev_priv(dev);             //lp 指向驱动程序的私有数据区        struct sk_buff *skb;                             // 申请skb_buff 指针        int status, length;          int ioaddr = dev->base_addr;                       // 得到cs8900 的基地址        status = readword(ioaddr, RX_FRAME_PORT);       // 获取cs8900 片上缓冲区的状态        length = readword(ioaddr, RX_FRAME_PORT);       // 获取cs8900 片上缓冲区的长度          if ((status & RX_OK) == 0) {          // 状态为接收错误,调用count_rx_errors 统计错误               count_rx_errors(status, lp);               return;        }          /* Malloc up new buffer. */        skb = dev_alloc_skb(length + 2); // 分配一个缓冲区,dev_alloc_skb 函数以 三、 net_rx 和 net_send_packet 3.1 net_rx 在这部分将介绍cs8900 驱动的两个最重要的函数,内核通过该两个函数实现了数据的收发。net_rx 函数的主要功能是从cs8900 的片上数据缓冲区中将数据传送给sk_buff 缓冲区,sk_buff 是网络驱动程序与Linux 内核通信的缓冲区。该结构可在<top_dir>\include\linux\skbuff.h 中找到。net_rx 函数的功能可总结如下:(该总结来源于:http://www.akae.cn/bbs/archiver/?tid-6657.html ) A .获取私有数据存放于lp 中; B .获取设备缓冲区状态和缓冲长度; C .如果状态不为RX_OK 则计数接收数据错误次数count_rx_error() D .分配一个sk_buf 区间 E .字对齐,skb_reserve() ; F .插入数据到接收口,insw() ; G .写入数据; H .初始化sk_buff 结构,eth_type_trans() I .进入上层接收函数netif_rx() ; J .初始化设备的计数;   net_rx 函数的注解如下所示: static void net_rx(struct net_device *dev) {        struct net_local *lp = netdev_priv(dev);             //lp 指向驱动程序的私有数据区        struct sk_buff *skb;                             // 申请skb_buff 指针        int status, length;          int ioaddr = dev->base_addr;                       // 得到cs8900 的基地址        status = readword(ioaddr, RX_FRAME_PORT);       // 获取cs8900 片上缓冲区的状态        length = readword(ioaddr, RX_FRAME_PORT);       // 获取cs8900 片上缓冲区的长度          if ((status & RX_OK) == 0) {    // 状态为接收错误,调用count_rx_errors 统计错误               count_rx_errors(status, lp);               return;        }          /* Malloc up new buffer. */        skb = dev_alloc_skb(length + 2);             // 分配一个缓冲区,dev_alloc_skb 函数以                    //GFP_ATOMIC 优先级调用alloc_skb 。alloc_skb 的功能为分配一个缓冲区                    // 并初始化skb->data ,skb->tail 和skb_head 域。dev_alloc_skb 和alloc_skb 的区                    // 别为,前者在skb->data 和skb_head 之间保留了一些空间,网络 层使用这                    // 一数据空间进行优化工作,驱动程序不该访问该空间。        if (skb == NULL) {    //skb 缓冲区分配失败? ……               lp->stats.rx_dropped++;  // 直接将丢包数加1               return;        }        skb_reserve(skb, 2);      /* longword align L3 header */    // 该函数增加skb 的data 和tail ,                // 该函数可填充缓冲区之 前保留报文头空间,大多数以太网在数据包之前                // 保留2 个字节,这样IP 头可在14 字节的以太网头之 后,在16 字节边界上对                // 齐。这里也空了两个字节,这两个自己加上14 字节的以太网头刚好16 字               // 节。 所以这里的主要作用是字对齐。        skb->dev = dev;          readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);  //skb_put 函             // 数的作用是更新skb 的 tail 和len 成员,也即在缓冲区尾部添加数据,该函数返             // 回skb->tail 的先前值。整句代码的含义为, 从cs8900 的数据缓冲区中读取       //length 个字节数据到skb 缓冲区。由于readwords 是以读取字(两个字 节)为             // 单位,所以length 应该保持字对齐,也即length 右移一位。        if (length & 1)       // 因为前面length 以字对齐,如果length 为单字节,                                    // 所以这里应该补上最后一个字节               skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT); ……         skb->protocol=eth_type_trans(skb,dev);  // 该函数定义在 linux/net/ethernet/eth.c 中,                                                  // 该处可参见linux 设备 驱动程序相关章节        netif_rx(skb);       // 通知内核已经接收到一个数据包,并封装入一个套接字缓冲区        dev->last_rx = jiffies;                    // 更新最后的接收包时间        lp->stats.rx_packets++;                // 接收的总数据包数加1        lp->stats.rx_bytes += length;         // 接收的字节数加上length }   3.1 net_send_packet        net_send_parcket 为内核提供了数据包发送功能,该函数在cs89x0_probe1 中被赋予了net_device 的hard_start_xmit 域,当内核需要发送数据包时,将调用dev-> hard_start_xmit 完成最后的数据包发送。该函数被调用的前提是,在调用该函数之前,内核已经将数据包放入了skb 缓冲区中。该函数的主要任务有: A .获取设备私有数据指针 B .加环形锁,spin_lock_irq() ; C .检测缓冲区是否为满,若满则调用netif_stop_queue() 暂停发送队列; D .写发送命令和发送长度,writeword() ; E .读取发送总线状态readreg() ; F .解环形锁,spin_unlock_irq() ; G .设置传输时钟计数; H .释放相应sk_buff, dev_kfree_skb(). 下面为此函数的简单注释: static int net_send_packet(struct sk_buff *skb, struct net_device *dev) {        struct net_local *lp = netdev_priv(dev);            // 获得驱动程序的私有数据   ……          spin_lock_irq(&lp->lock);         // 获得自旋锁,以便进入临界区        netif_stop_queue(dev);    // 通知内核暂停内核与驱动程序间的数据传递,也即告诉                                               // 内核不要向skb 缓冲区填充数据。          /* initiate a transmit sequence */  // 初始化cs8900 的发送对列,主要为写命令和数                                                          // 据长度,为数据发送做准备        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 * /       // 查看cs8900 是否为                                                                                       // 发送分配了地址空间。        if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {            …….               spin_unlock_irq(&lp->lock);               if (net_debug) printk("cs89x0: Tx buffer not free!\n");               return 1;        }        /* Write the contents of the packet */        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);   // 将数                                                                                                                // 据交给cs8900 发送        spin_unlock_irq(&lp->lock);         // 发送结束,释放自旋锁        lp->stats.tx_bytes += skb->len;    // 累加发送的总字节数        dev->trans_start = jiffies;             // 更新最后的传输时间        dev_kfree_skb (skb);                  // 发送完毕,释放skb 缓冲区     ……        return 0; } 总结:        在cs8900 驱动中,主要简解了驱动程序中的部分重要函数,包括初始化、打开/ 关闭网络驱动和发送/ 接收数据。对于其余的驱动程序代码,如超时处理、状态获取等函数没做解释,它们的实现也比较简单。由于自己板子上没有EEPROM ,所以也没有分析与EEPROM 相关部分的代码。DMA 部分好像编译进去会错,所以也没有去分析,以后有时间再去弄弄DMA 部分。                                                                                               The End                                                                                              ------ anmnmnly                                                                                              ------ 2007.12.16
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载