打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
dm9000驱动 简析1

dm9000的驱动

   首先,在linux的源代码的arch/arm/mach-smdk2416.c中,有 个

static struct platform_device *smdk2416_devices[] __initdata =

{
    &s3c_device_spi0,
   &s3c_device_spi1,
    &s3c_device_wdt,
    &s3c_device_i2c,
    &s3c_device_lcd,
    &s3c_device_rtc,
    &s3c_device_adc,
    &s3c_device_iis,
    &s3c_device_usbgadget,
    &s3c_device_usb,
    &s3c_device_hsmmc0,  
    &s3c_device_hsmmc1,         
    &s3c_device_dm9000,   
};

      这个是s3c2416的板子启动的时候用到的外围的部件吧,我们有dm9000了(s3c_device_dm9000),这些都是启动的时候注册到内核的platform_device 设备;

    在 /arch/arm/plat-s3c24xx/devs.c 中,可以找到dm9000的资源(设备需要的内存 中断等)

static struct resource s3c_dm9000_resources[] = {
      [0] = {
              .start  = S3C_PA_SMC9115+0x300,        //16bit IO address 0x20000300
              .end    = S3C_PA_SMC9115 + 0x301,
              .flags  = IORESOURCE_MEM,
      },
      [1] = {
              .start  = S3C_PA_SMC9115+0x308,        //16 bit Data address 0x20000308
              .end    = S3C_PA_SMC9115 + 0x309,
              .flags  = IORESOURCE_MEM,
      },
      [2] = {
              .start = IRQ_EINT3,
              .end   = IRQ_EINT3,
              .flags = IORESOURCE_IRQ| IORESOURCE_IRQ_HIGHLEVEL,
      },
};

struct platform_device s3c_device_dm9000 =
{
      .name           = "dm9000",
      .id             =  -1,
      .num_resources  = ARRAY_SIZE(s3c_dm9000_resources),
      .resource       = s3c_dm9000_resources,
};

EXPORT_SYMBOL(s3c_device_dm9000);

    可以看到有 地址寄存器,有数据寄存器,还有中断;

    下面就是在dm9000.c中的驱动部分了, 首先 module_init(dm9000_init);

static struct platform_driver dm9000_driver = {
    .driver    = {
       .name    = "dm9000",
        .owner     = THIS_MODULE,
    },
    .probe   = dm9000_probe,
    .remove  = dm9000_drv_remove,
    .suspend = dm9000_drv_suspend,
    .resume  = dm9000_drv_resume,
};

static int __init
dm9000_init(void)
{
    printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);

    return platform_driver_register(&dm9000_driver);   
}

    在init中我们注册了dm9000驱动名字是 dm9000 与设备dm9000的名字匹配,则调用probe 初始化dm9000的硬件;

static int

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;

unsigned long base;

int ret = 0;

int iosize;

int i;

u32 id_val;

 

/* Init network device */

ndev = alloc_etherdev(sizeof (struct board_info));

if (!ndev) {

printk("%s: could not allocate device.\n", CARDNAME);

return -ENOMEM;

}

 

SET_MODULE_OWNER(ndev);

SET_NETDEV_DEV(ndev, &pdev->dev);

 

PRINTK2("dm9000_probe()\n");

 

/* setup board info structure */

db = (struct board_info *) ndev->priv;

memset(db, 0, sizeof (*db));

 

spin_lock_init(&db->lock);

 

if (pdev->num_resources < 2) {

ret = -ENODEV;

goto out;

else if (pdev->num_resources == 2) 

{

base = pdev->resource[0].start;

 

if (!request_mem_region(base, 4, ndev->name)) {

ret = -EBUSY;

goto out;

}

 

ndev->base_addr = base;

ndev->irq = pdev->resource[1].start;

db->io_addr = (void __iomem *)base;

db->io_data = (void __iomem *)(base + 4);

 

else 

{

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) {

printk(KERN_ERR PFX "insufficient resources\n");

ret = -ENOENT;

goto out;

}

 

i = res_size(db->addr_res);

db->addr_req = request_mem_region(db->addr_res->start, i,

 pdev->name);

 

if (db->addr_req == NULL) {

printk(KERN_ERR PFX "cannot claim address reg area\n");

ret = -EIO;

goto out;

}

 

db->io_addr = ioremap(db->addr_res->start, i);

 

if (db->io_addr == NULL) {

printk(KERN_ERR "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) {

printk(KERN_ERR PFX "cannot claim data reg area\n");

ret = -EIO;

goto out;

}

 

db->io_data = ioremap(db->data_res->start, iosize);

 

if (db->io_data == NULL) {

printk(KERN_ERR "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;

 

PRINTK2("dm9000_probe iosize: %X\n",iosize);

s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_EINT3);

s3c2410_gpio_pullup(S3C2410_GPF3, 0);  /* pull-up/down disable */

/* 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;

}

 

dm9000_reset(db);

 

/* try two times, DM9000 sometimes gets the first read wrong */

for (i = 0; i < 2; 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;

printk("%s: read wrong id 0x%08x\n", CARDNAME, id_val);

}

 

if (id_val != DM9000_ID) {

printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val);

goto release;

}

 

PRINTK2("dm9000_probe id: %X\n",id_val);

/* 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->get_stats = &dm9000_get_stats;

ndev->set_multicast_list = &dm9000_hash_table;

#ifdef CONFIG_NET_POLL_CONTROLLER

ndev->poll_controller = &dm9000_poll_controller;

#endif

 

#ifdef DM9000_PROGRAM_EEPROM

program_eeprom(db);

#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;

 

/* Read SROM content */

for (i = 0; i < 64; i++)

((u16 *) db->srom)[i] = read_srom_word(db, i);

 

/* Set Node Address */

for (i = 0; i < 6; i++)

ndev->dev_addr[i] = db->srom[i];

 

if (!is_valid_ether_addr(ndev->dev_addr)) {

/* try reading from mac */

 

for (i = 0; i < 6; i++)

ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

}

 

if (!is_valid_ether_addr(ndev->dev_addr))

printk("%s: Invalid ethernet MAC address.  Please "

      "set using ifconfig\n", ndev->name);

 

platform_set_drvdata(pdev, ndev);

ret = register_netdev(ndev);

 

if (ret == 0) {

printk("%s: dm9000 at %p,%p IRQ %d MAC: ",

      ndev->name,  db->io_addr, db->io_data, ndev->irq);

for (i = 0; i < 5; i++)

printk("%02x:", ndev->dev_addr[i]);

printk("%02x\n", ndev->dev_addr[5]);

}

return 0;

 

 release:

 out:

printk("%s: not found (%d).\n", CARDNAME, ret);

 

dm9000_release_board(pdev, db);

kfree(ndev);

 

return ret;

}

捡主要的记下来 有个struct board_info 的结构体比较特殊,他记录网卡的一些信息

typedef struct board_info {

 

void __iomem*io_addr;/* Register I/O base address */

void __iomem*io_data;/* Data I/O address */

u16irq;/* IRQ */

 

u16tx_pkt_cnt;

u16queue_pkt_len;

u16queue_start_addr;

u16dbug_cnt;

u8io_mode;/* 0:word, 2:byte */

u8phy_addr;

u8imr_all;

 

unsigned intflags;

unsigned intin_suspend :1;

intdebug_level;

 

enum dm9000_type type;

 

void (*inblk)(void __iomem *port, void *data, int length);

void (*outblk)(void __iomem *port, void *data, int length);

void (*dumpblk)(void __iomem *port, int length);

 

struct device*dev;    /* parent device */

 

struct resource*addr_res;   /* resources found */

struct resource *data_res;

struct resource*addr_req;   /* resources requested */

struct resource *data_req;

struct resource *irq_res;

 

struct mutexaddr_lock;/* phy and eeprom access lock */

 

struct delayed_work phy_poll;

struct net_device  *ndev;

 

spinlock_tlock;

 

struct mii_if_info mii;

u32msg_enable;

struct net_device_stats stats;//add by leo HOOK

} board_info_t;

并且他是下面的网卡 ndev = alloc_etherdev( ) 的私有信息,priv;ndev = alloc_etherdev(sizeof(struct board_info)); 会类似与应用编程的中的malloc申请一段内存,

struct net_device *alloc_etherdev(int sizeof_priv)

{

return alloc_netdev(sizeof_priv, "eth%d", ether_setup);

}


struct net_device *alloc_netdev(int sizeof_priv, const char *name,

void (*setup)(struct net_device *))

{

void *p;

struct net_device *dev;

int alloc_size;

 

BUG_ON(strlen(name) >= sizeof(dev->name));

 

/* ensure 32-byte alignment of both the device and private area */

alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;//32byte 对齐

alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;

 

p = kzalloc(alloc_size, GFP_KERNEL);

if (!p) {

printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");

return NULL;

}

 

dev = (struct net_device *)

(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);

dev->padded = (char *)dev - (char *)p;

 

if (sizeof_priv)

dev->priv = netdev_priv(dev);

 

setup(dev);

strcpy(dev->name, name);

return dev;

}


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux DM9000网卡驱动程序完全分析
Linux设备驱动简析--dm9000网卡驱动 - Network - Neil Chiao's Blog
以太网驱动程序
DM9000 驱动移植及源码简析
linux 网络设备驱动-steven
xilinx 的socket CAN驱动介绍
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服