#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>

//设备资源(设备描述)
static struct resource led_resources[]={
    [0]={
        .start = 0x0,
        .end = 0xA,
        .flags = IORESOURCE_MEM
    },
    [1]={
        .start = 0xB,
        .end = 0xF,
        .flags = IORESOURCE_IRQ
    },
    [2]={
        .start = 0xAA,
        .end = 0xAF,
        .flags = IORESOURCE_IRQ
    }
};
static void led_device_release(struct device *dev)
{
    printk("led_device_release\n");
}

static struct platform_device led_device = {
    .name = "led_device",
    .id = -1,
    .resource = led_resources,
    .dev = {
        .release = led_device_release,
    },
};
static int led_module_init(void)
{
    platform_device_register(&led_device);
    printk("hello world\n");
    return 0;
}
static void led_module_exit(void)
{
    platform_device_unregister(&led_device);
    printk("goodbye world\n");
}

module_init(led_module_init);
module_exit(led_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("WYL");
MODULE_DESCRIPTION("led device");
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/uaccess.h>
dev_t dev_no; // 设备号
struct cdev cdev_test; // 字符设备结构体

struct class *class_test; // 类
struct device *device_test; // 设备
static int test_open(struct inode *inode,struct file *file)
{
    printk("open\n");
    return 0;
}
static ssize_t test_read(struct file *file,char __user *buf, size_t size,loff_t *off){
    printk("read\n");
    return 0;
}
static ssize_t test_write(struct file *file,const char __user *buf, size_t size,loff_t *off){
    printk("write\n");
    *off += size;
    return size;
}
static int test_release(struct inode *inode,struct file *file)
{
    printk("release\n");
    return 0;
}
struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = test_open,
    .read = test_read,
    .write = test_write,
    .release = test_release,
};
int my_probe(struct platform_device * dev){
    
    int ret;
    ret = alloc_chrdev_region(&dev_no, 0, 1, "led_device");
    if (ret<0) {
        printk("alloc_chrdev_region failed\n");
        return ret;
    }
    printk("major:%d, minor:%d\n", MAJOR(dev_no), MINOR(dev_no));
    cdev_init(&cdev_test, &fops);
    cdev_add(&cdev_test, dev_no, 1);

    class_test = class_create(THIS_MODULE, "led_device"); //创建类
    device_test = device_create(class_test, NULL, dev_no, NULL, "led_device");

    printk("my_probe"); //device和driver匹配成功时调用
    return 0;
}
int my_remove(struct platform_device * dev){
    
    printk("my_remove"); //移除设备或这个驱动被rmmod时调用
    return 0;
};
struct platform_driver driver_test= {
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "led_device", //与device设备描述名字一致!!!
        .owner = THIS_MODULE,

        // const struct platform_device_id *id_table; //非必须,匹配时优先级最高比上面的name要高
    }
};
static int platform_driver_init(void)
{
    platform_driver_register(&driver_test);
    printk("platform_driver_init");
    return 0;
}
static void platform_driver_exit(void)
{
    // 1. 先销毁设备节点
    device_destroy(class_test, dev_no);
    
    // 2. 销毁类 (原代码缺失此步,必须添加)
    class_destroy(class_test);
    
    // 3. 删除字符设备
    cdev_del(&cdev_test);
    
    // 4. 最后注销设备号
    unregister_chrdev_region(dev_no, 1);
    platform_driver_unregister(&driver_test);
    printk("platform_driver_exit");
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);

// 模块许可证声明,必须是 GPL 兼容的许可证才能加载到内核中
MODULE_LICENSE("GPL");
// 模块作者信息
MODULE_AUTHOR("wyl");
// 模块描述
MODULE_DESCRIPTION("A simple Hello World Linux Driver");