【linux驅動分析】之dm9000驅動分析(一):dm9000原理及硬件分析
【linux驅動分析】之dm9000驅動分析(二):定義在板文件中的資源和設備以及幾個宏
【linux驅動分析】之dm9000驅動分析(三):sk_buff結構分析
【linux驅動分析】之dm9000驅動分析(四):net_device結構體
【linux驅動分析】之dm9000驅動分析(五):另外幾個重要的結構體
【linux驅動分析】之dm9000驅動分析(六):dm9000_init和dm9000_probe的實現
【linux驅動分析】之dm9000驅動分析(七):dm9000的卸載掛起和恢復以及打開和停止
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 #endif 72 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 #endif 89 };
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)
其中的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);