基于fs210平台的dm9000原理及移植

作者:杨老师,华清远见教育科技集团讲师。

dm9000的原理图如下:

网卡的移植工作很简单,首先是需要添加目标版的平台设备信息,就可以实现网卡的移植工作,平台设备信息如何添加很重要

添加平台信息的第一步是添加一个platform_device设备信息

首先在arch/arm/mach-s5pv210/mach-smdkv210.c

添加头文件:

#include <linux/dm9000.h>
        #include <linux/irq.h>
        添加platform_device平台设备信息
        struct platform_device {
                const char * name; // 平台设备名称
                int id; // 设备的ID 如果是唯一设备,ID = -1,如果设备不是唯一的,ID = 0,1,2,3,4,5
                struct device dev; //
                u32 num_resources; //所拥有资源结构体的个数
                struct resource * resource; //资源结构体指针
                const struct platform_device_id *id_entry;
                struct pdev_archdata archdata;
        };
        例如:
        static struct platform_device s5pc100_device_dm9000 = {
                .name = "dm9000",
                .id = -1,
                .num_resources = ARRAY_SIZE(dm9000_resources),
                .resource = dm9000_resources,
                .dev = {
                .        platform_data = &s5pc100_dm9000_platdata,
                }
        };

struct device 在 include/linux/device.h中的platform_data只是一个指针,可以传送一个地址

用这个地址可以给驱动传动一些特殊的数据,对于dm9000这个网卡芯片需要传送dm9000_plat_data

在网卡驱动中使用了如下的定义:  struct dm9000_plat_data *pdata = pdev->dev.platform_data;

因此我们要传递这个这个platform_data结构体,结构体的定义如下:

/* platform data for platform device structure's platform_data field */
        struct dm9000_plat_data {
                unsigned int flags;
                unsigned char dev_addr[6]; // 网卡的mac地址 ,可以不写,如果不写的话,是随机生成一个
                /* allow replacement IO routines */
                void (*inblk)(void __iomem *reg, void *data, int len);
                void (*outblk)(void __iomem *reg, void *data, int len);
                void (*dumpblk)(void __iomem *reg, int len);
        };

这个是网卡驱动使用的结构体

flags = DM9000_PLATF_16BITONLY, 表示dm9000工作在16位的模式下

在这个文件中定义 include/linux/dm9000.h

/* IO control flags */
        #define DM9000_PLATF_8BITONLY (0x0001)
        #define DM9000_PLATF_16BITONLY (0x0002)
        #define DM9000_PLATF_32BITONLY (0x0004)
        #define DM9000_PLATF_EXT_PHY (0x0008)
        #define DM9000_PLATF_NO_EEPROM (0x0010)
        #define DM9000_PLATF_SIMPLE_PHY (0x0020) /* Use NSR to find LinkStatus */
        dev_addr是网卡的mac地址,
        .dev_addr[0] = 0x00,
        .dev_addr[1] = 0x00,
        .dev_addr[2] = 0x3e,
        .dev_addr[3] = 0x26,
        .dev_addr[4] = 0x0a,
        .dev_addr[5] = 0x00,
        例如:.dev = {
                .platform_data = & s5pc100_dm9000_plat data,  //表示驱动中要用的数据
        }
        struct resource {
                resource_size_t start; // 表示资源的开始值
                resource_size_t end; // 表示资源的结束值
                const char *name;
                unsigned long flags; // 资源的类型
                struct resource *parent, *sibling, *child;
        };
        我们一般只关心这3个字段 start ,end ,flags
        flags:
        /*
        * IO resources have these defined flags.
        */
        #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
        #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
        #define IORESOURCE_IO 0x00000100
        #define IORESOURCE_MEM 0x00000200 //内存资源
        #define IORESOURCE_IRQ 0x00000400 //中断资源
        #define IORESOURCE_DMA 0x00000800
        #define IORESOURCE_BUS 0x00001000
        因为在驱动中使用了如下的函数:
        db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        因此我们必须要对成员设置如下:
        static struct resource dm9000_resources[] = {
                [0] = {
                        .start = 0x88000000,
                        .end = 0x88000000+0x3,
                        .flags = IORESOURCE_MEM,
                },
                [1] = {
                        .start = 0x88000000+0x4,
                        .end = 0x88000000+0x4+0x3,
                        .flags = IORESOURCE_MEM,
                },
                [2] = {
                        .start = IRQ_EINT(10),
                        .end = IRQ_EINT(10),
                        .flags = IORESOURCE_IRQ|IRQ_TYPE_LEVEL_HIGH,
                },
        };

为什么驱动要这样设置呢?

因为网卡dm9000这个设备有一个接口, 是dm9000的cmd引脚, 如果cmd = 0 表示的是地址, cmd=1 表示的数据

cmd这个引脚接到了addr2 ,接到了地址总线, 也就是说我们只需要对addr2的地址产生影响就可以了,因此addr2 =0 表示是index是地址,

addr2 =1 表示对index索引指向的寄存器的内的值data ,因此我们只需要对这两个寄存器设置就可以实现网卡的驱动.

int platform_device_register(struct platform_device *pdev); //注册一个设备

int platform_add_devices(struct platform_device **pdevs, int ndev); //注册多个设备

pdevs: platform_device类型的指针

ndev : 一共有多少个设备