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 : 一共有多少个设备