(1) 首先需要定义一个驱动设备的资源信息:
struct platform_device {
const char * name;
u32 id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
例如定义at91网络设备:
static struct resource eth_resources[] = {
[0] = {
.start = AT91SAM9260_BASE_EMAC,
.end = AT91SAM9260_BASE_EMAC + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91SAM9260_ID_EMAC,
.end = AT91SAM9260_ID_EMAC,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device at91sam9260_eth_device = {
.name = "macb",
.id = -1,
.dev = {
.dma_mask = ð_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = ð_data,
},
.resource = eth_resources,
.num_resources = ARRAY_SIZE(eth_resources),
};
这里定义了IORESOURCE_MEM(IO地址范围)和IORESOURCE_IRQ(中断号)两个资源。这两个资源可以通过调用platform_get_resource和platform_get_irq获取,如:
/* Get I/O base address and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//res是指向struct resource结构的指针。
irq = platform_get_irq(pdev, 0);
//irq即是中断号。
//注:platform_get_resource和platform_get_irq的第二个参数是资源的序号。
(2) 添加Platform_device到驱动:
platform_device_register(&at91sam9260_eth_device);
(3) 定义Platform_driver
static struct platform_driver at91ether_driver = {
.probe = at91ether_probe,
.remove = __devexit_p(at91ether_remove),
.suspend = at91ether_suspend,
.resume = at91ether_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
这里指定的DRV_NAME必须和platform_device结构中的name一致,否则不能找到驱动。
(4) 注册platform_driver
static int __init at91ether_init(void)
{
return platform_driver_register(&at91ether_driver);
}
static void __exit at91ether_exit(void)
{
platform_driver_unregister(&at91ether_driver);
}
module_init(at91ether_init)
module_exit(at91ether_exit)
platform_driver_register成功执行后将执行at91ether_probe。
(5) 在at91ether_probe中做驱动的初始化工作。如在at91的mac驱动中初始化一个net_device并调用register_netdev(dev):
static const struct net_device_ops at91ether_netdev_ops = {
.ndo_open = at91ether_open,
.ndo_stop = at91ether_close,
.ndo_start_xmit = at91ether_start_xmit,
.ndo_get_stats = at91ether_stats,
.ndo_set_multicast_list = at91ether_set_multicast_list,
.ndo_set_mac_address = set_mac_address,
.ndo_do_ioctl = at91ether_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = at91ether_poll_controller,
#endif
};
static int __init at91ether_setup( …
{
struct net_device *dev;
…
ether_setup(dev);
dev->netdev_ops = &at91ether_netdev_ops;
/* Register the network interface */
ret = register_netdev(dev);
…
}