【linux驱动分析】之dm9000驱动分析(一):dm9000原理及硬件分析
【linux驱动分析】之dm9000驱动分析(二):定义在板文件中的资源和设备以及几个宏
【linux驱动分析】之dm9000驱动分析(三):sk_buff结构分析
【linux驱动分析】之dm9000驱动分析(四):net_device结构体
【linux驱动分析】之dm9000驱动分析(五):另外几个重要的结构体
【linux驱动分析】之dm9000驱动分析(六):dm9000_init和dm9000_probe的实现
【linux驱动分析】之dm9000驱动分析(七):dm9000的卸载挂起和恢复以及打开和停止
硬件平台:友善之臂Tiny6410核心板 + DM9000EP软件平台:linux-2.6.38交叉编译器:Friendly ARM提供的arm-linux-gcc 4.5.1一、源代码(mach-mini6410.c)
1 /* Ethernet */ 2 #ifdef CONFIG_DM9000 3 #define S3C64XX_PA_DM9000 (0x18000000) 4 #define S3C64XX_SZ_DM9000 SZ_1M 5 #define S3C64XX_VA_DM9000 S3C_ADDR(0x03b00300) 6 7 static struct resource dm9000_resources[] = { 8 [0] = { 9 .start = S3C64XX_PA_DM9000,10 .end = S3C64XX_PA_DM9000 + 3,11 .flags = IORESOURCE_MEM,12 },13 [1] = {14 .start = S3C64XX_PA_DM9000 + 4,15 .end = S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,16 .flags = IORESOURCE_MEM,17 },18 [2] = {19 .start = IRQ_EINT(7),20 .end = IRQ_EINT(7),21 .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,22 },23 };24 25 static struct dm9000_plat_data dm9000_setup = {26 .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_EXT_PHY,27 .dev_addr = { 0x08, 0x90, 0x00, 0xa0, 0x90, 0x90 },28 };29 30 static struct platform_device s3c_device_dm9000 = {31 .name = "dm9000",32 .id = 0,33 .num_resources = ARRAY_SIZE(dm9000_resources),34 .resource = dm9000_resources,35 .dev = {36 .platform_data = &dm9000_setup,37 }38 };39 40 static int __init dm9000_set_mac(char *str) {41 unsigned char addr[6];42 unsigned int val;43 int idx = 0;44 char *p = str, *end;45 46 while (*p && idx < 6) {47 val = simple_strtoul(p, &end, 16);48 if (end <= p) {49 /* convert failed */50 break;51 } else {52 addr[idx++] = val;53 p = end;54 if (*p == ':'|| *p == '-') {55 p++;56 } else {57 break;58 }59 }60 }61 62 if (idx == 6) {63 printk("Setup ethernet address to %pM\n", addr);64 memcpy(dm9000_setup.param_addr, addr, 6);65 }66 67 return 1;68 }69 70 __setup("ethmac=", dm9000_set_mac);71 #endif72 73 static struct map_desc mini6410_iodesc[] = {74 {75 /* LCD support */76 .virtual = (unsigned long)S3C_VA_LCD,77 .pfn = __phys_to_pfn(S3C_PA_FB),78 .length = SZ_16K,79 .type = MT_DEVICE,80 },81 #ifdef CONFIG_DM9000 /*这里的定义不知道是做什么用的*/82 {83 .virtual = (u32)S3C64XX_VA_DM9000,84 .pfn = __phys_to_pfn(S3C64XX_PA_DM9000),85 .length = S3C64XX_SZ_DM9000,86 .type = MT_DEVICE,87 },88 #endif89 };DM9000的设备会在platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));里统一注册。二、下面分析一下上面代码中红色的宏或者函数1、ARRAY_SIZE#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof( (arr)[0] ) + __must_be_array(arr) )它是定义在include/linux/kernel.h中的一个宏,用来计算数组中元素的个数。__must_be_array是编译器相关的,用来防止传入的参数不是数组,比如说传入了指针,这样的话可能回编译不通过(猜测)。2、simple_strtoul/** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)simple_strtoul是定义在lib/vsprintf.c中的函数,它的作用是把一个字符串转换为unsigned long型的整数,并返回。
其中的endp参数存放解析后的字符串地址,base参数,是要转换的进制数。vsprintf.c里还定义了其他好多字符串处理的函数,具体用到时去查。3、__setup它是定义在include/linux/init.h中的一个宏:#define __setup(str, fn) \ __setup_param(str, fn, fn, 0)其中:str是关键字,fn是关联处理函数。__setup只是告诉内核在启动时输入串中含有str时,内核要去执行fn。Str必须以“=”符结束以使parse_args更方便解析。紧随“=”后的任何文本都会作为输入传给fn。
例如本例中的:__setup("ethmac=", dm9000_set_mac);关于__setup的更多分析见《__setup宏的作用》可你仍然感谢天地和人世所带来的这些变化和发生。