该驱动基于linux-2.6.24.4内核。
首先,需要在arch/arm/mach-s3c2410/mach-smdk2410.c文件中添加如下代码:
static struct resource s3c_dm9000_resource [] = {
[0] = {
.start = 0x10000000,
.end = 0x10000040,
.flags = IORESOURCE_MEM
},
[1] = {
.start = IRQ_EINT2,
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
}
};
注意上面的start、end等地址是指的网卡的物理地址。然后,还要在该文件中加入如下代码:
struct platform_device s3c_device_dm9000 = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_dm9000_resource),
.resource = s3c_dm9000_resource,
};
需要特别注意上面的name字段,当设备驱动程序寻找设别资源时,会根据该字段对设备进行匹配。另外,该文件中的smdk2410_devices[]数组中,还需要加入s3c_device_dm9000,不然系统启动时没有找到该资源就不会调用相应的probe函数。
下面分析驱动程序的probe函数。若驱动被编译进内核,则在系统启动的时候,该函数会被调用。该函数的源代码如下:
static int dm9k_drv_probe( struct platform_device * pdev) { struct net_device * ndev; unsigned long base; unsigned int * addr = NULL ; int ret = - ENODEV; ndev = alloc_etherdev( sizeof ( struct board_info) ) ; if ( ! ndev) { printk( "%s: could not allocate device./n" , CARDNAME) ; return - ENOMEM; } ndev- > dma = ( unsigned char ) - 1; if ( pdev- > num_resources < 2 | | pdev- > num_resources > 3) { printk( "DM9000: Wrong num of resources %d/n" , pdev- > num_resources) ; ret = - ENODEV; goto out; } base = pdev- > resource[ 0] . start; ndev- > irq = pdev- > resource[ 1] . start; /* * Request the regions. */ if ( ! request_mem_region( base, 4, ndev- > name) ) { ret = - EBUSY; goto out; } addr = ioremap( base, 4) ; if ( ! addr) { ret = - ENOMEM; goto release_mem; } ret = dm9k_probe( ndev, ( unsigned long ) addr) ; if ( ret ! = 0) { iounmap( addr) ; release_mem: release_mem_region( base, 4) ; out: printk( "%s: not found (%d)./n" , CARDNAME, ret) ; kfree( ndev) ; } return ret; }
函数首先调用alloc_etherdev,该函数在include/linux/etherdevice.h中声明,其中有如下语句:
# define alloc_etherdev( sizeof_priv) alloc_etherdev_mq( sizeof_priv, 1)
而alloc_etherdev_mq函数又定义在net/ethernet/eth.c中,如下:
struct net_device * alloc_etherdev_mq( int sizeof_priv, unsigned int queue_count) { return alloc_netdev_mq( sizeof_priv, "eth%d" , ether_setup, queue_count) ; }
可见,该函数只是用自己的参数来调用alloc_netdev_mq函数。alloc_netdev_mq函数定义在net/core/dev.c中,原型如下:
struct net_device * alloc_netdev_mq( int sizeof_priv, const char * name, void ( * setup) ( struct net_device * ) , unsigned int queue_count)
关于该函数的说明:
/** * alloc_netdev_mq - allocate network device * @sizeof_priv: size of private data to allocate space for * @name: device name format string * @setup: callback to initialize device * @queue_count: the number of subqueues to allocate * * Allocates a struct net_device with private data area for driver use * and performs basic initialization. Also allocates subquue structs * for each queue on the device at the end of the netdevice. */
可见,
alloc_etherdev为设备驱动分配了私有数据空间,并对设备驱动做了一些初始化工作。
接下来,设备驱动将要检查设备的resources的数量,如果数量小于2或者大于3,则初始化函数自动返回,初始化失败。我们的设备驱动中,resources的数量为2:一个表示设备的IO地址,另一个是设备的中断号。
代码
base = pdev- > resource[ 0] . start; ndev- > irq = pdev- > resource[ 1] . start;
分别得到设备的端口地址和中断号。
接下来,驱动程序将向系统申请io内存,从地址base开始,大小为4个字节。如果申请成功,接下来需要做的就是将地址重新映射,从地址base开始,长度为4个字节。这样做的原因主要是驱动程序一般不直接访问物理地址,而访问虚拟地址。地址重新映射成功后,就调用dm9k_probe函数进行设备初始化。