转自http://blog.csdn.net/yinwei520/article/details/6262931
一、硬件链接情况
DM9000在电路板上的连接中与编程相关的如下:
1)EECS拉高:16bit模式;
2)INT连接到2440 EINT18:INT脚为低时为有效中断信号,中断线为EINT18
3)cs连接到2440的nGCS4,CMD连接2440地址总线ADDR[2]:知道上面这些信息已经足够移植驱动了。
二、platform驱动模型
从Linux 2.6起引入了一套新的驱动管理和注册机制:Platform_device和Platform_driver。Linux中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver进行注册。
Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。
Platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。通过Platform机制开发发底层驱动的大致流程为: 定义 platform_device à 注册 platform_device à 定义 platform_driver à注册 platform_driver。
首先要确认的就是设备的资源信息,例如设备的地址,中断号等。
在2.6内核中platform设备用结构体platform_device来描述,该结构体定义在kernel/include/linux/platform_device.h中,
struct platform_device {
const char * name;
u32 id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,
struct resource {
const char *name;
unsigned long start, end;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
一个独立的挂接在cpu总线上的设备单元,一般都需要一段线性的地址空间来描述设备自身,linux是怎么管理所有的这些外部"物理地址范围段",进而给用户和linux自身一个比较好的观察4G总线上挂接的一个个设备实体的简洁、统一级联视图的呢?
linux采用struct resource结构体来描述一个挂接在cpu总线上的设备实体(32位cpu的总线地址范围是0~4G):
resource->start描述设备实体在cpu总线上的线性起始物理地址;
resource->end -描述设备实体在cpu总线上的线性结尾物理地址;
resource->name 描述这个设备实体的名称,这个名字开发人员可以随意起,但最好贴切;
resource->flag 描述这个设备实体的一些共性和特性的标志位;
问题:我怎样知道设备实体在cpu总线上的线性起始物理地址跟线性结尾物理地址?
通过查看原理图吗??如果是,那具体应该怎样分析呢?
三、现在分析dm9000在Linux内核中的结构。
static struct platform_device与static struct platform_resources结构体在arch/arm/plat-s3c24xx/devs.c中定义,在arch/arm/plat-s3c/include/plat/devs.h中声明,在arch/arm/mach-s3c2440/mach-smdk2440.c中使用(通过函数:platform_add_devices()注册进内核)。
至于platform_driver的实现就是在dm900.c中实现了。
四、移植
从上图可以看出
a. dm9000的访问地址为BANK4的基址(也许是通过上面的nGCS4看出来的)。(这个我是不明白的)
b. 只有一根地址线ADDR2。
c. 总线位宽为16位,有nWAIT信号。
d. 使用中断引脚为EINT18(使用LAN_INT实现的)。
一 增加DM9000平台设备
增加平台设备前首先要先定义该平台设备,这主要修改arch/arm/plat-s3c24xx/devs.c文件。
1.添加头文件 ,在devs.c文件的头文件引入处添加如下代码:
#include <linux/dm9000.h>
2.定义dm9000平台资源 ,在devs.c文件的合适处添加如下代码(其实看一下源文件就知道合适的意思):
- 1. /* DM9000 */
- 2. static struct resource s3c_dm9k_resource[] = {
- 3. [0] = {
- 4. .start = S3C2410_CS4,
- 5. .end = S3C2410_CS4 + 3,
- 6. .flags = IORESOURCE_MEM,
- 7. },
- 8. [1] = {
- 9. .start = S3C2410_CS4 + 4,
- 10. .end = S3C2410_CS4 + 4 + 3,
- 11. .flags = IORESOURCE_MEM,
- 12. },
- 13. [2] = {
- 14. .start = IRQ_EINT7,
- 15. .end = IRQ_EINT7,
- 16. .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
- 17. }
- 18.
- 19. };
- 20.
- 21. /* for the moment we limit ourselves to 16bit IO until some
- 22. * better IO routines can be written and tested
- 23. */
- 24.
- 25. static struct dm9000_plat_data s3c_dm9k_platdata = {
- 26. .flags = DM9000_PLATF_16BITONLY,
- 27. };
- 28.
- 29. struct platform_device s3c_device_dm9k = {
- 30. .name = "dm9000",
- 31. .id = 0,
- 32. .num_resources = ARRAY_SIZE(s3c_dm9k_resource),
- 33. .resource = s3c_dm9k_resource,
- 34. .dev = {
- 35. .platform_data = &s3c_dm9k_platdata,
- 36. }
- 37. };
- 38.
- 39. EXPORT_SYMBOL(s3c_device_dm9k);
NOTE:
a.s3c_dm9k_resource数组定义了3个资源:两个内存空间和一个中断号。数组项0、1定义了访问dm9000时使用的地址。在dm9000的芯片手册上有如下的介绍:
CMD Command Type
When high, the access of this command cycle is DATA port
When low, the access of this command cycle is ADDRESS port
所以数组项0、1的.start域就容易理解了,S3C2410_CS4中addr2为0,表示传输地址;S3C2410_CS4 + 4中addr2为1,表示传输数据。数组项[2]定义的中断号就较容易理解。
b.结构s3c_dm9k_platdata中指定了数据总线宽度为16。
c.结构s3c_device_dm9k就是dm9000的平台设备,其中.resource和.dev项分别指向前面定义的s3c_dm9k_resource和s3c_dm9k_platdata。
3.把定义的平台设备加入到内核设备列表中 ,在common-smdk.c文件的smdk_devs数组中添加一下代码:(我的为mach-mini2440.c文件mini2440_devices数组)
&s3c_device_dm9k,
这样,系统启动时就会把这个数组中的设备注册到内核中。
二 修改dm9000.c文件
对dm9000的枚举最终由dm9000_probe函数来实现。
1.添加头文件 ,在dm9000.c的头文件引入处增加以下代码,定义了一些寄存器的宏定义:
view plain copy to clipboard print ?
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
view plaincopy to clipboardprint?
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
2.修改probe函数 ,通过设置存储控制器使BANK4可用,修改后的dm9000_probe函数如下,其中修改的地方都由CONFIG_ARCH_S3C2410包括:
- view plaincopy to clipboardprint?
- # *
- # * Search DM9000 board, allocate space and register it
- # */
- # static int __devinit
- # dm9000_probe(struct platform_device *pdev)
- # {
- # struct dm9000_plat_data *pdata = pdev->dev.platform_data;
- # struct board_info *db; /* Point a board information structure */
- # struct net_device *ndev;
- # const unsigned char *mac_src;
- # int ret = 0;
- # int iosize;
- # int i;
- # u32 id_val;
- #
- # # if defined(CONFIG_ARCH_S3C2410)
- # unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
- # unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
- # # endif
- #
- # /* Init network device */
- # ndev = alloc_etherdev(sizeof(struct board_info));
- # if (!ndev) {
- # dev_err(&pdev->dev, "could not allocate device./n");
- # return -ENOMEM;
- # }
- #
- # SET_NETDEV_DEV(ndev, &pdev->dev);
- #
- # dev_dbg(&pdev->dev, "dm9000_probe()/n");
- #
- # #if defined(CONFIG_ARCH_S3C2410)
- # *((volatile unsigned int *)S3C2410_BWSCON) =
- # (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- # *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- # #endif
- #
- # /* setup board info structure */
- # db = netdev_priv(ndev);
- # memset(db, 0, sizeof(*db));
- #
- # db->dev = &pdev->dev;
- # db->ndev = ndev;
- #
- # spin_lock_init(&db->lock);
- # mutex_init(&db->addr_lock);
- #
- # INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
- #
- # 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);
- #
- # if (db->addr_res == NULL || db->data_res == NULL ||
- # db->irq_res == NULL) {
- # dev_err(db->dev, "insufficient resources/n");
- # ret = -ENOENT;
- # goto out;
- # }
- #
- # iosize = res_size(db->addr_res);
- # db->addr_req = request_mem_region(db->addr_res->start, iosize,
- # pdev->name);
- #
- # if (db->addr_req == NULL) {
- # dev_err(db->dev, "cannot claim address reg area/n");
- # ret = -EIO;
- # goto out;
- # }
- #
- # db->io_addr = ioremap(db->addr_res->start, iosize);
- #
- # if (db->io_addr == NULL) {
- # dev_err(db->dev, "failed to ioremap address reg/n");
- # ret = -EINVAL;
- # goto out;
- # }
- #
- # iosize = res_size(db->data_res);
- # db->data_req = request_mem_region(db->data_res->start, iosize,
- # pdev->name);
- #
- # if (db->data_req == NULL) {
- # dev_err(db->dev, "cannot claim data reg area/n");
- # ret = -EIO;
- # goto out;
- # }
- #
- # db->io_data = ioremap(db->data_res->start, iosize);
- #
- # if (db->io_data == NULL) {
- # dev_err(db->dev, "failed to ioremap data reg/n");
- # ret = -EINVAL;
- # goto out;
- # }
- #
- # /* fill in parameters for net-dev structure */
- # ndev->base_addr = (unsigned long)db->io_addr;
- # ndev->irq = db->irq_res->start;
- #
- # /* ensure at least we have a default set of IO routines */
- # dm9000_set_io(db, iosize);
- #
- # /* check to see if anything is being over-ridden */
- # if (pdata != NULL) {
- # /* check to see if the driver wants to over-ride the
- # * default IO width */
- #
- # if (pdata->flags & DM9000_PLATF_8BITONLY)
- # dm9000_set_io(db, 1);
- #
- # if (pdata->flags & DM9000_PLATF_16BITONLY)
- # dm9000_set_io(db, 2);
- #
- # if (pdata->flags & DM9000_PLATF_32BITONLY)
- # dm9000_set_io(db, 4);
- #
- # /* check to see if there are any IO routine
- # * over-rides */
- #
- # if (pdata->inblk != NULL)
- # db->inblk = pdata->inblk;
- #
- # if (pdata->outblk != NULL)
- # db->outblk = pdata->outblk;
- #
- # if (pdata->dumpblk != NULL)
- # db->dumpblk = pdata->dumpblk;
- #
- # db->flags = pdata->flags;
- # }
- #
- # #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
- # db->flags |= DM9000_PLATF_SIMPLE_PHY;
- # #endif
- #
- # dm9000_reset(db);
- #
- # /* try multiple times, DM9000 sometimes gets the read wrong */
- # for (i = 0; i < 8; i++) {
- # id_val = ior(db, DM9000_VIDL);
- # id_val |= (u32)ior(db, DM9000_VIDH) << 8;
- # id_val |= (u32)ior(db, DM9000_PIDL) << 16;
- # id_val |= (u32)ior(db, DM9000_PIDH) << 24;
- #
- # if (id_val == DM9000_ID)
- # break;
- # dev_err(db->dev, "read wrong id 0x%08x/n", id_val);
- # }
- #
- # if (id_val != DM9000_ID) {
- # dev_err(db->dev, "wrong id: 0x%08x/n", id_val);
- # ret = -ENODEV;
- # goto out;
- # }
- #
- # /* Identify what type of DM9000 we are working on */
- #
- # id_val = ior(db, DM9000_CHIPR);
- # dev_dbg(db->dev, "dm9000 revision 0x%02x/n", id_val);
- #
- # switch (id_val) {
- # case CHIPR_DM9000A:
- # db->type = TYPE_DM9000A;
- # break;
- # case CHIPR_DM9000B:
- # db->type = TYPE_DM9000B;
- # break;
- # default:
- # dev_dbg(db->dev, "ID %02x => defaulting to DM9000E/n", id_val);
- # db->type = TYPE_DM9000E;
- # }
- #
- # /* from this point we assume that we have found a DM9000 */
- #
- # /* driver system function */
- # ether_setup(ndev);
- #
- # ndev->open = &dm9000_open;
- # ndev->hard_start_xmit = &dm9000_start_xmit;
- # ndev->tx_timeout = &dm9000_timeout;
- # ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
- # ndev->stop = &dm9000_stop;
- # ndev->set_multicast_list = &dm9000_hash_table;
- # ndev->ethtool_ops = &dm9000_ethtool_ops;
- # ndev->do_ioctl = &dm9000_ioctl;
- #
- # #ifdef CONFIG_NET_POLL_CONTROLLER
- # ndev->poll_controller = &dm9000_poll_controller;
- # #endif
- #
- # db->msg_enable = NETIF_MSG_LINK;
- # db->mii.phy_id_mask = 0x1f;
- # db->mii.reg_num_mask = 0x1f;
- # db->mii.force_media = 0;
- # db->mii.full_duplex = 0;
- # db->mii.dev = ndev;
- # db->mii.mdio_read = dm9000_phy_read;
- # db->mii.mdio_write = dm9000_phy_write;
- #
- # #if defined(CONFIG_ARCH_S3C2410)
- # printk("Now use the default MAC address: 08:90:90:90:90:90/n");
- # mac_src = "friendly-arm";
- # ndev->dev_addr[0] = 0x08;
- # ndev->dev_addr[1] = 0x90;
- # ndev->dev_addr[2] = 0x90;
- # ndev->dev_addr[3] = 0x90;
- # ndev->dev_addr[4] = 0x90;
- # ndev->dev_addr[5] = 0x90;
- # #else
- # mac_src = "eeprom";
- #
- # /* try reading the node address from the attached EEPROM */
- # for (i = 0; i < 6; i += 2)
- # dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
- #
- # if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
- # mac_src = "platform data";
- # memcpy(ndev->dev_addr, pdata->dev_addr, 6);
- # }
- #
- # if (!is_valid_ether_addr(ndev->dev_addr)) {
- # /* try reading from mac */
- #
- # mac_src = "chip";
- # for (i = 0; i < 6; i++)
- # ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
- # }
- #
- # if (!is_valid_ether_addr(ndev->dev_addr))
- # dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
- # "set using ifconfig/n", ndev->name);
- # #endif
- #
- # platform_set_drvdata(pdev, ndev);
- # ret = register_netdev(ndev);
- #
- # if (ret == 0)
- # printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)/n",
- # ndev->name, dm9000_type_to_char(db->type),
- # db->io_addr, db->io_data, ndev->irq,
- # ndev->dev_addr, mac_src);
- # return 0;
- #
- # out:
- # #if defined(CONFIG_ARCH_S3C2410)
- # *(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
- # *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
- # #endif
- # dev_err(db->dev, "not found (%d)./n", ret);
- #
- # dm9000_release_board(pdev, db);
- # free_netdev(ndev);
- #
- # return ret;
- # }
- # *
- # * Search DM9000 board, allocate space and register it
- # */
- # static int __devinit
- # dm9000_probe(struct platform_device *pdev)
- # {
- # struct dm9000_plat_data *pdata = pdev->dev.platform_data;
- # struct board_info *db; /* Point a board information structure */
- # struct net_device *ndev;
- # const unsigned char *mac_src;
- # int ret = 0;
- # int iosize;
- # int i;
- # u32 id_val;
- #
- # # if defined(CONFIG_ARCH_S3C2410)
- # unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
- # unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
- # # endif
- #
- # /* Init network device */
- # ndev = alloc_etherdev(sizeof(struct board_info));
- # if (!ndev) {
- # dev_err(&pdev->dev, "could not allocate device./n");
- # return -ENOMEM;
- # }
- #
- # SET_NETDEV_DEV(ndev, &pdev->dev);
- #
- # dev_dbg(&pdev->dev, "dm9000_probe()/n");
- #
- # #if defined(CONFIG_ARCH_S3C2410)
- # *((volatile unsigned int *)S3C2410_BWSCON) =
- # (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- # *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- # #endif
- #
- # /* setup board info structure */
- # db = netdev_priv(ndev);
- # memset(db, 0, sizeof(*db));
- #
- # db->dev = &pdev->dev;
- # db->ndev = ndev;
- #
- # spin_lock_init(&db->lock);
- # mutex_init(&db->addr_lock);
- #
- # INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
- #
- # 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);
- #
- # if (db->addr_res == NULL || db->data_res == NULL ||
- # db->irq_res == NULL) {
- # dev_err(db->dev, "insufficient resources/n");
- # ret = -ENOENT;
- # goto out;
- # }
- #
- # iosize = res_size(db->addr_res);
- # db->addr_req = request_mem_region(db->addr_res->start, iosize,
- # pdev->name);
- #
- # if (db->addr_req == NULL) {
- # dev_err(db->dev, "cannot claim address reg area/n");
- # ret = -EIO;
- # goto out;
- # }
- #
- # db->io_addr = ioremap(db->addr_res->start, iosize);
- #
- # if (db->io_addr == NULL) {
- # dev_err(db->dev, "failed to ioremap address reg/n");
- # ret = -EINVAL;
- # goto out;
- # }
- #
- # iosize = res_size(db->data_res);
- # db->data_req = request_mem_region(db->data_res->start, iosize,
- # pdev->name);
- #
- # if (db->data_req == NULL) {
- # dev_err(db->dev, "cannot claim data reg area/n");
- # ret = -EIO;
- # goto out;
- # }
- #
- # db->io_data = ioremap(db->data_res->start, iosize);
- #
- # if (db->io_data == NULL) {
- # dev_err(db->dev, "failed to ioremap data reg/n");
- # ret = -EINVAL;
- # goto out;
- # }
- #
- # /* fill in parameters for net-dev structure */
- # ndev->base_addr = (unsigned long)db->io_addr;
- # ndev->irq = db->irq_res->start;
- #
- # /* ensure at least we have a default set of IO routines */
- # dm9000_set_io(db, iosize);
- #
- # /* check to see if anything is being over-ridden */
- # if (pdata != NULL) {
- # /* check to see if the driver wants to over-ride the
- # * default IO width */
- #
- # if (pdata->flags & DM9000_PLATF_8BITONLY)
- # dm9000_set_io(db, 1);
- #
- # if (pdata->flags & DM9000_PLATF_16BITONLY)
- # dm9000_set_io(db, 2);
- #
- # if (pdata->flags & DM9000_PLATF_32BITONLY)
- # dm9000_set_io(db, 4);
- #
- # /* check to see if there are any IO routine
- # * over-rides */
- #
- # if (pdata->inblk != NULL)
- # db->inblk = pdata->inblk;
- #
- # if (pdata->outblk != NULL)
- # db->outblk = pdata->outblk;
- #
- # if (pdata->dumpblk != NULL)
- # db->dumpblk = pdata->dumpblk;
- #
- # db->flags = pdata->flags;
- # }
- #
- # #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
- # db->flags |= DM9000_PLATF_SIMPLE_PHY;
- # #endif
- #
- # dm9000_reset(db);
- #
- # /* try multiple times, DM9000 sometimes gets the read wrong */
- # for (i = 0; i < 8; i++) {
- # id_val = ior(db, DM9000_VIDL);
- # id_val |= (u32)ior(db, DM9000_VIDH) << 8;
- # id_val |= (u32)ior(db, DM9000_PIDL) << 16;
- # id_val |= (u32)ior(db, DM9000_PIDH) << 24;
- #
- # if (id_val == DM9000_ID)
- # break;
- # dev_err(db->dev, "read wrong id 0x%08x/n", id_val);
- # }
- #
- # if (id_val != DM9000_ID) {
- # dev_err(db->dev, "wrong id: 0x%08x/n", id_val);
- # ret = -ENODEV;
- # goto out;
- # }
- #
- # /* Identify what type of DM9000 we are working on */
- #
- # id_val = ior(db, DM9000_CHIPR);
- # dev_dbg(db->dev, "dm9000 revision 0x%02x/n", id_val);
- #
- # switch (id_val) {
- # case CHIPR_DM9000A:
- # db->type = TYPE_DM9000A;
- # break;
- # case CHIPR_DM9000B:
- # db->type = TYPE_DM9000B;
- # break;
- # default:
- # dev_dbg(db->dev, "ID %02x => defaulting to DM9000E/n", id_val);
- # db->type = TYPE_DM9000E;
- # }
- #
- # /* from this point we assume that we have found a DM9000 */
- #
- # /* driver system function */
- # ether_setup(ndev);
- #
- # ndev->open = &dm9000_open;
- # ndev->hard_start_xmit = &dm9000_start_xmit;
- # ndev->tx_timeout = &dm9000_timeout;
- # ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
- # ndev->stop = &dm9000_stop;
- # ndev->set_multicast_list = &dm9000_hash_table;
- # ndev->ethtool_ops = &dm9000_ethtool_ops;
- # ndev->do_ioctl = &dm9000_ioctl;
- #
- # #ifdef CONFIG_NET_POLL_CONTROLLER
- # ndev->poll_controller = &dm9000_poll_controller;
- # #endif
- #
- # db->msg_enable = NETIF_MSG_LINK;
- # db->mii.phy_id_mask = 0x1f;
- # db->mii.reg_num_mask = 0x1f;
- # db->mii.force_media = 0;
- # db->mii.full_duplex = 0;
- # db->mii.dev = ndev;
- # db->mii.mdio_read = dm9000_phy_read;
- # db->mii.mdio_write = dm9000_phy_write;
- #
- # #if defined(CONFIG_ARCH_S3C2410)
- # printk("Now use the default MAC address: 08:90:90:90:90:90/n");
- # mac_src = "friendly-arm";
- # ndev->dev_addr[0] = 0x08;
- # ndev->dev_addr[1] = 0x90;
- # ndev->dev_addr[2] = 0x90;
- # ndev->dev_addr[3] = 0x90;
- # ndev->dev_addr[4] = 0x90;
- # ndev->dev_addr[5] = 0x90;
- # #else
- # mac_src = "eeprom";
- #
- # /* try reading the node address from the attached EEPROM */
- # for (i = 0; i < 6; i += 2)
- # dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
- #
- # if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
- # mac_src = "platform data";
- # memcpy(ndev->dev_addr, pdata->dev_addr, 6);
- # }
- #
- # if (!is_valid_ether_addr(ndev->dev_addr)) {
- # /* try reading from mac */
- #
- # mac_src = "chip";
- # for (i = 0; i < 6; i++)
- # ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
- # }
- #
- # if (!is_valid_ether_addr(ndev->dev_addr))
- # dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
- # "set using ifconfig/n", ndev->name);
- # #endif
- #
- # platform_set_drvdata(pdev, ndev);
- # ret = register_netdev(ndev);
- #
- # if (ret == 0)
- # printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)/n",
- # ndev->name, dm9000_type_to_char(db->type),
- # db->io_addr, db->io_data, ndev->irq,
- # ndev->dev_addr, mac_src);
- # return 0;
- #
- # out:
- # #if defined(CONFIG_ARCH_S3C2410)
- # *(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
- # *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
- # #endif
- # dev_err(db->dev, "not found (%d)./n", ret);
- #
- # dm9000_release_board(pdev, db);
- # free_netdev(ndev);
- #
- # return ret;
- # }
a.第24-27行定义了两个变量,用来保存BWSCON和BANKCON4的值,下面将会用到。
b.第32-39对BANK4进行了设置。首先设置BWSCON,
9对BANK4进行了设置。首先设置BWSCON,
- #if defined(CONFIG_ARCH_S3C2410)
- *((volatile unsigned int *)S3C2410_BWSCON) =
- (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- #endif
- view plaincopy to clipboardprint?
- #if defined(CONFIG_ARCH_S3C2410)
- *((volatile unsigned int *)S3C2410_BWSCON) =
- (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- #endif
- #if defined(CONFIG_ARCH_S3C2410)
- *((volatile unsigned int *)S3C2410_BWSCON) =
- (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- #endif
主要是设置了总线宽度16,nWAIT,ST。(具体的可以参考s3c2440数据手册的BUS WIDTH & WAIT CONTROL REGISTER (BWSCON))。然后设置BANKCON4的时间参数,值为0×1f7c(pmc:normal Tacp:6clk Tcah:4clk Tcoh:1clk Tacc:14clk Tcos:4clk 具体可以参考s3c2440数据手册的BANK CONTROL REGISTER)
c.第209-216的代码是我自己给注释的,据其意思,上面首先给MAC赋值,然后检测合法性,但经实践,判断语句总成立,所以在linux启动注册dm9000时总输出Invalid ethernet MAC address.反正后面也会再次给MAC地址赋值,所以干脆把这几行代码注释掉。
d.第218-227行就是给MAC地址赋值的,听说赋什么值都可以,有这么神奇吗?
e.第266-269行恢复寄存器原来的值。
f.以上的步骤和代码都是参考书上的,但可惜的是,按照上面步骤去修改,系统能成功加载dm9000驱动,但无法ping通,这个事确实让我很苦恼,上网找了很多资料,最后发现大多数都需要调用writel来设置BWSCON、GPFCON和中断等。所以无计之下参考了mini2440中的一段代码,出自附送光盘的无操作系统代码测试的dm9000部分。
到此 ,代码的移植到此为止,然后是配置内核,以使用dm9000。在
-> Device Drivers
--> Network device support
--> Network device support (NETDEVICES [=y])
--> Ethernet (10 or 100Mbit) 处将DM9000网卡选为编译进内核。
然后在/etc/init.d/rcS文件的开始处加入
ifconfig
eth0 192.168.1.22<
pre>
当然,ip地址是因人而定的,尽量设为和PC在同一个网段。重新将内核下载到开发板后启动