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;
}
联系客服