韦东山2440-学习笔记-platform
1. 简介
platform是 设备驱动总线模型
2. 示例
#include <linux/platform_device.h>
#include <linux/module.h>
static struct platform_device *led_dev;
static struct resource led_dev_resource[] = {
{
// gpfcon gpfdat
.start = 0x56000050,
.end = 0x56000050 + 8,
.flags = IORESOURCE_MEM,
},
{
// pin
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ,
}
};
static int __init
led_dev_init(void)
{
led_dev = platform_device_alloc("led", -1);
platform_device_add_resources(led_dev,
led_dev_resource,
sizeof(led_dev_resource)/sizeof(*led_dev_resource));
platform_device_add(led_dev);
return 0;
}
static void __exit
led_dev_exit(void)
{
platform_device_unregister(led_dev);
platform_device_put(led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/bootmem.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/module.h>
static unsigned int *gpfcon;
static unsigned int *gpfdat;
static unsigned int pin;
static struct class *led_class;
static dev_t dev;
static ssize_t
led_write (struct file *fp, const char __user *user,
size_t sz, loff_t *offset)
{
unsigned int val, ret;
ret = copy_from_user(&val, user, sz);
if (val == 1)
*gpfdat &= ~(1 << pin);
else
*gpfdat |= (1 << pin);
return 0;
}
static int
led_open (struct inode *inode, struct file *fp)
{
printk("led open\n");
*gpfcon &= ~(0x3 << 2 * pin);
*gpfcon |= (1 << 2*pin);
return 0;
}
static const struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
};
// 当总线的match匹配时,调用
static int
led_drv_probe(struct platform_device *pdev)
{
struct resource *res;
struct cdev *cdev;
printk("led match.\n");
// 获得硬件资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpfcon = ioremap(res->start, res->end - res->start);
gpfdat = gpfcon + 1;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
pin = res->start;
// cdev
alloc_chrdev_region(&dev, 0, 1, "led");
cdev = cdev_alloc();
cdev->owner = THIS_MODULE;
cdev->ops = &led_ops;
cdev_add(cdev, dev, 1);
printk("major : %d\n", MAJOR(dev));
// 自动创建设备节点
led_class = class_create(THIS_MODULE, "led");
device_create(led_class, NULL, dev, "led%d", pin);
return 0;
}
// 当已经匹配的 dev 或 drv 调用 platform_xxx_unregister 时,调用此函数
static int
led_drv_remove(struct platform_device *pdev)
{
printk("led remove.\n");
device_destroy(led_class, dev);
class_destroy(led_class);
unregister_chrdev(MAJOR(dev), "led"); // 释放设备号 和 cdev
iounmap(gpfcon);
return 0;
}
static struct platform_driver led_drv = {
.probe = led_drv_probe,
.remove = led_drv_remove,
.driver = {
.name = "led",
},
};
static int __init
led_init(void)
{
platform_driver_register(&led_drv);
return 0;
}
static void __exit
led_exit(void)
{
platform_driver_unregister(&led_drv);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");