Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1068645
  • 博文数量: 139
  • 博客积分: 1823
  • 博客等级: 上尉
  • 技术积分: 3403
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 09:54
文章存档

2014年(7)

2013年(16)

2012年(48)

2011年(68)

分类:

2011-08-22 14:55:57

1.1.1          步骤四:分析DM9000的网卡驱动程序

驱动程序共包含三个文件dm9000x.c dm9000.c dm9000.h,都存放在drivers/net/目录下,其中dm9000x.c 主要包括以下函数:

 

底层硬件操作函数:这些函数与硬件相关,与驱动程序编写相关不大。 

void            outb(unsigned char value, unsigned long addr)

void            outw(unsigned short value, unsigned long addr)

unsigned char     inb(unsigned long addr)

unsigned short    inw(unsigned long addr)

 

u8 ior(board_info_t *db, int reg)   // Read a byte from I/O port

void iow(board_info_t *db, int reg, u8 value) //   Write a byte to I/O port

 

 

驱动程序的函数接口,

int init_module(void) //加载设备驱动程序

void cleanup_module(void) //卸载设备驱动程序

 

static void dmfe_init_dm9000(struct DEVICE *dev) /* Initilize DM910X board */

dmfe_probe(struct DEVICE *dev) //初始化net_device 结构体

static int dmfe_open(struct DEVICE *dev)

static int dmfe_stop(struct DEVICE *dev)

static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) //发送一个数据包

static void dmfe_packet_receive(struct DEVICE *dev, board_info_t *db) //接收数据包,被中断调用

 

 

其中int init_module(void)函数调用了dmfe_probe(struct DEVICE *dev)来初始化net_device结构体

if(strcmp(dev->name,"eth0")==0)

         if(strcmp(dev->name,"eth1")==0)

         if(strcmp(dev->name,"eth3")==0)

                  

         outb(DM9000_VID_L, iobase);

         id_val = inb(iobase + 4);

         outb(DM9000_VID_H, iobase);

         id_val |= inb(iobase + 4) << 8;

         outb(DM9000_PID_L, iobase);

         id_val |= inb(iobase + 4) << 16;

         outb(DM9000_PID_H, iobase);

         id_val |= inb(iobase + 4) << 24;

 

         if (id_val == DM9000_ID) {

             printk("HHTech DM9000 %s I/O: %x,VID: %x,MAC: ", dev->name,iobase, id_val);

             dm9000_count++;

             /* Init network device */

             dev = init_etherdev(dev, 0);

 

         /* Allocated board information structure */

       irqline = 3;

         db = (void *)(kmalloc(sizeof(*db), GFP_KERNEL|GFP_DMA));

         memset(db, 0, sizeof(*db));

         dev->priv = db;   /* link device and board info */

         db->next_dev = dmfe_root_dev;

         dmfe_root_dev = dev;

         db->ioaddr = iobase;

         db->io_data = iobase + 4;

 

         /* driver system function */

         dev->base_addr = iobase;

         //dev->irq = 68; //INT4 166;//irqline;

         dev->open = &dmfe_open;

         dev->hard_start_xmit = &dmfe_start_xmit;

         dev->stop = &dmfe_stop;

         dev->get_stats = &dmfe_get_stats;

         dev->set_multicast_list = &dm9000_hash_table;

         dev->do_ioctl = &dmfe_do_ioctl;

 

 

dmfe_open(struct DEVICE *dev)中,申请了中断处理程序,然后调用了

dmfe_init_dm9000(dev);初始化DM9000芯片。

static int dmfe_open(struct DEVICE *dev)

{      

if(request_irq(dev->irq, &dmfe_interrupt,SA_INTERRUPT/*SA_SHIRQ*/,

"DM9000 device",dev))

                   return -EAGAIN;

/* Initilize DM910X board */

       dmfe_init_dm9000(dev);

 

netif_wake_queue(dev);         //add by simon 2001.9.4 for kernel 2.4

MOD_INC_USE_COUNT;

}

 

Stop()方法停止网络驱动程序:

static int dmfe_stop(struct DEVICE *dev)

{

netif_stop_queue(dev);  //add by simon 2001.9.4 for kernel 2.4

 

         /* free interrupt */

         free_irq(dev->irq, dev);

 

         /* RESET devie */

         phy_write(db, 0x00, 0x8000);        /* PHY RESET */

         iow(db, 0x1f, 0x01);     /* Power-Down PHY */

         iow(db, 0xff, 0x80);      /* Disable all interrupt */

         iow(db, 0x05, 0x00);    /* Disable RX */

 

         MOD_DEC_USE_COUNT;

return 0;

}

发送数据接口,对照前面的简单的驱动框架。

static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)

{

netif_stop_queue(dev); //add by simon 2001.9.4 for kernel 2.4

 

         /* Disable all interrupt */

         iow(db, 0xff, 0x80);

 

         /* Move data to DM9000 TX RAM */

         data_ptr = (char *)skb->data;

         outb(0xf8, db->ioaddr);

         tmplen = (skb->len + 1) / 2;

         /* Word mode*/

         for (i = 0; i < tmplen; i++)

                      outw(((u16 *)data_ptr)[i], db->io_data);

        

         /* TX control: First packet immediately send, second packet queue */

         if (db->tx_pkt_cnt == 0) {

                   /* First Packet */

                   db->tx_pkt_cnt++;

 

                   /* Set TX length to DM9000 */

                   iow(db, 0xfc, skb->len & 0xff);

                   iow(db, 0xfd, (skb->len >> 8) & 0xff);

 

                   /* Issue TX polling command */

                   iow(db, 0x2, 0x1);        /* Cleared after TX complete */

 

                   dev->trans_start = jiffies;      /* saved the time stamp */

         } else {

                   /* Second packet */

                   db->tx_pkt_cnt++;

                   db->queue_pkt_len = skb->len;

         }

         /* free this SKB */

         dev_kfree_skb(skb);

 

       /* Re-enable resource check */

         if (db->tx_pkt_cnt == 1)

         netif_wake_queue(dev);   //add by simon 2001.9.4 for kernel 2.4

                  

         /* Re-enable interrupt mask */

         iow(db, 0xff, 0x83);

 

         return 0;

}

 

中断处理程序,用来接收数据

static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{      

         db = (board_info_t *)dev->priv;

         spin_lock(&db->lock); // add by simon 2001.9.4 for kernel 2.4

 

         /* Save previous register address */

         reg_save = inb(db->ioaddr);

 

         /* Disable all interrupt */

         iow(db, 0xff, 0x80);

 

         /* Got DM9000 interrupt status */

         int_status = ior(db, 0xfe);               /* Got ISR */

         iow(db, 0xfe, int_status);                /* Clear ISR status */

         //printk("I%x ", int_status);

 

         /* Received the coming packet */

         if (int_status & 1)

                   dmfe_packet_receive(dev, db);

                  

         /* Trnasmit Interrupt check */

         if (int_status & 2) {

                   tx_status = ior(db, 0x01);      /* Got TX status */

                   if (tx_status & 0xc) {

                            /* One packet sent complete */

                            db->tx_pkt_cnt--;

                            dev->trans_start = 0;

                            db->stats.tx_packets++;

 

                            /* Queue packet check & send */

                            if (db->tx_pkt_cnt > 0) {

                                     iow(db, 0xfc, db->queue_pkt_len & 0xff);

                                     iow(db, 0xfd, (db->queue_pkt_len >> 8) & 0xff);

                                     iow(db, 0x2, 0x1);

                                     dev->trans_start = jiffies;

                            }

 

                            //dev->tbusy = 0;         /* Active upper layer, send again */

                            //mark above by simon 2001.9.4 for kernel 2.4

                            netif_wake_queue(dev);

                            //mark_bh(NET_BH); //mark by simon 2001.9.4

                   }

         }

         /* Re-enable interrupt mask */

         iow(db, 0xff, 0x83);

 

         /* Restore previous register address */

         outb(reg_save, db->ioaddr);

 

1.1.2          步骤五:调试运行DM9000网卡驱动程序

在内核的DM9000驱动代码中,直接增加调试和打印信息,然后重新编译内核,下载到开发板上,察看调试信息。内核中的打印输出语句用printk()

把内核中的DM9000的网络驱动程序/drivers/net/dm9000x.c中的注释掉的printk语句打开。详细见dm9000x.c文件。

 

第一步,打印网络的配置信息,与ifconfig显示的信息比较。

1, /kernel/drivers/net/dm9000x.c中,注释掉的printk有效。主要是在dmfe_probe(struct DEVICE *dev)函数中的打印信息.

2, 然后再/kernel目录下编译内核,make zImage

3, 通过TFTP下载刚编译的内核镜像zImage到开发板中

tftp 30008000 zImage

tftp 30800000 ramdisk.image.gz

go 30008000

 

4,观察系统启动时有网络驱动程序打印出来的信息。进入系统后用ifconfig察看网络信息。

 

第二步:观察中断调用,数据接收的情况

1, /kernel/drivers/net/dm9000x.c中,使宏定义有效

//#undef DM9000_DEBUG   

#define DM9000_DEBUG

主要是在

static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)

static void dmfe_packet_receive(struct DEVICE *dev, board_info_t *db)

中的打印信息, 注释掉的printk有效.

2, 然后再/kernel目录下编译内核,make zImage

3, 通过TFTP下载刚编译的内核镜像zImage到开发板中

tftp 30008000 zImage

tftp 30800000 ramdisk.image.gz

go 30008000

4,观察系统启动时有网络驱动程序打印出来的信息。进入系统后挂载NFS系统(如果还没有挂载NFS),可以看到打印出网络中断和数据接收的信息。

 

第二步:用户层调用网络socket接口。

1,  因为操作系统封装了网络设备驱动程序,用户层只能通过socket接口使用网络。 HHARM2410-STUDY\modules.TestApp\ethernet-performance-test提供了测试网络流量的测试程序,使用了socket接口。

2,  分别编译HHARM2410-STUDY\modules.TestApp\ethernet-performance-test\run-on-boardHHARM2410-STUDY\modules.TestApp\ethernet-performance-test\run-on-LINUX-PC

3,开发板用网线(对接线)同PC机相连;

PC机上编译好eth-perf-pc/中的程序,生成server可执行程序,运行

./server

minicom下执行客户端程序(开发板上)

./client 192.168.2.111 –t 1 –p 1

其中192.168.2.111PC机的IP,-t表示time-p表示package

4,如果这时候没有注释掉网络驱动程序dm9000的中断和接收数据的打印信息,屏幕会频繁的提示产生中断和接收到数据。

还可以用

[localhost]# cat /prop/interrupts

察看中断使用情况,可以看到网络驱动程序使用中断号,和使用次数。

阅读(1410) | 评论(0) | 转发(0) |
0

上一篇:关于linux内存管理

下一篇:Linux 进程管理

给主人留下些什么吧!~~