【demo】基于platform的misc driver

【demo】基于platform的misc driver


platform是Linux内的一种虚拟总线,称为platform总线,包含platform_device设备和platform_driver驱动两个对象,用于将驱动和设备分开,实现内核分离的思想。

一个成熟的字符设备驱动往往是把platform 跟字符注册程序结合起来,这里演示基于platform的misc driver的使用。

1 platform

platform总线的匹配优先级是:of_match_table > id_table > name

static struct platform_driver xx_driver = {
    
    
    .probe = xx_probe,
    .remove = xx_remove,
    .id_table = tbl,              ;2
    .driver = {
    
    
        .name = "phoenix",        ;3
        .of_match_table = NULL,   ;1
    },
};

其中

  • of_match_table ;主要用于和device tree 匹配
  • id_table ;用于和 struct platform_device 匹配,也就是设备树诞生之前的一种匹配方式
  • driver.name ;用于和 struct platform_device 匹配,只不过是单一匹配,多设备用id_table

下面是platform的多设备demo

dev0.c

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

static struct resource dres[] = {
    
    
	[0] = {
    
    
		.name = "dev0",
		.start = 0x23010000,
		.end = 0x23010000 + 0xffff,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
    
    
		.name = "dev0",
		.start = 19,
		.end = 22,
		.flags = IORESOURCE_IRQ,
	},
};

static void release(struct device *dev)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	return ;
}

static struct platform_device devc=
{
    
    
	.name = "phoenix0",
    .id = 0,
    .dev.release = release,
	.num_resources = ARRAY_SIZE(dres),
	.resource = dres,
};

static int heo_init(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	return platform_device_register(&devc);
}

static void heo_exit(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	platform_device_unregister(&devc);
	return;
}

module_init(heo_init);
module_exit(heo_exit);
MODULE_LICENSE("GPL");

dev1.c

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

static struct resource dres[] = {
    
    
	[0] = {
    
    
		.name = "dev1",
		.start = 0x23020000,
		.end = 0x23020000 + 0xffff,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
    
    
		.name = "dev1",
		.start = 85,
		.end = 88,
		.flags = IORESOURCE_IRQ,
	},
};

static void release(struct device *dev)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	return ;
}

static struct platform_device devc=
{
    
    
	.name = "phoenix1",
    .id = 1,
    .dev.release = release,
	.num_resources = ARRAY_SIZE(dres),
	.resource = dres,
};

static int heo_init(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	return platform_device_register(&devc);
}

static void heo_exit(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	platform_device_unregister(&devc);
	return;
}

module_init(heo_init);
module_exit(heo_exit);
MODULE_LICENSE("GPL");

driver.c

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

static int hello_probe(struct platform_device *pdev)
{
    
    
    printk("%s %d, match ok, %d, %s\n", __func__, __LINE__, pdev->id, pdev->name);
    return 0;
}

static int hello_remove(struct platform_device *pdev)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
	return 0;
}

static struct platform_device_id tbl[] = {
    
    
    {
    
    "phoenix0"},
    {
    
    "phoenix1"},
    {
    
    },
};

static struct platform_driver hello_driver = {
    
    
    .probe = hello_probe,
    .remove = hello_remove,
    .id_table = tbl,
    .driver = {
    
    
        .name = "phoenix",
    },
};

static int hello_init(void)
{
    
    
    printk("%s %d\n", __func__, __LINE__);
	return platform_driver_register(&hello_driver);
}

static void hello_exit(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
    platform_driver_unregister(&hello_driver);
    return;
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

Makefile

ARCH := arm64
ARMCC := aarch64-linux-gnu-
KDIR := ${HOME}/xxx/kernel

ifneq  ($(KERNELRELEASE),)

obj-m:=dev0.o dev1.o driver.o
$(info "2nd")

else

PWD:=$(shell pwd)
all:
	$(info "1st")
	make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(ARMCC) modules

.PHONY:clean
clean:
	rm -rf *.ko *.o *.symvers *.mod.c *.mod.o *.order .tmp_versions .*.cmd
endif

2 misc

misc注册字符设备的方式比直接使用alloc_chrdev_region方式简便很多,最起码可以少敲几行代码。

扫描二维码关注公众号,回复: 15218611 查看本文章

misc+platform方式管理的driver,使用设备号关联struct inode 和struct miscdevice之间的关系,设备号的操作函数如下。

#include <linux/kdev_t.h>

  • (dev_t)–>主设备号、次设备号
    • MAJOR(dev_t dev);
    • MINOR(dev_t dev);
  • 主设备号、次设备号–>(dev_t)
    • MKDEV(int major,int minor);

关联结构体

struct miscdevice  {
    
          
    int minor;  //次设备号
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;  //当前设备,是device_create的返回值
};

struct inode {
    
    
	...
    atomic_t i_count;
	...
    dev_t i_rdev;   //该成员表示设备文件的inode结构,它包含了真正的设备编号。
    loff_t i_size;
	...
    const struct inode_operations *i_op;
    const struct file_operations *i_fop; /* former->i_op->default_file_ops */
	...
    struct list_head i_devices;
    union {
    
    
        struct pipe_inode_info *i_pipe;
        struct block_device *i_bdev;
        struct cdev *i_cdev; //该成员表示字符设备的内核的内部结构。
    };
	...
	void *i_private; /* fs or device private pointer */
};

**Note:**一定要确保struct platform_deviceid 值跟 struct miscdevice 数组下标呼应。

跟上面platform的程序相比,只需要改下driver.c 即可

driver.c

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
static int dmisc_open(struct inode *inode, struct file *filp)
{
    
    
    printk("%s %d, pdev %d %d %d\n", __func__, __LINE__, inode->i_rdev, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
    return 0;
}
static int dmisc_release(struct inode *inode, struct file *filp)
{
    
    
    printk ("%s %d\n", __func__, __LINE__);
    return 0;
}
static ssize_t dmisc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    
    
	printk ("%s %d\n", __func__, __LINE__);
    return 0;
}
static ssize_t dmisc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    
    
	printk ("%s %d\n", __func__, __LINE__);
    return 0;
}
static long dmisc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    
    
    printk ("%s %d\n", __func__, __LINE__);
    return 0;
}

static struct file_operations drv_ops= {
    
    
	.owner = THIS_MODULE,
    .open = dmisc_open,
    .read = dmisc_read,
    .write = dmisc_write,
    .release = dmisc_release,
	.unlocked_ioctl = dmisc_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = dmisc_ioctl,
#endif
};

static struct miscdevice misc[] = {
    
    
    {
    
    
        .minor = MISC_DYNAMIC_MINOR,
        .name = "phx0",
        .fops = &drv_ops,
    },
    {
    
    
        .minor = MISC_DYNAMIC_MINOR,
        .name = "phx1",
        .fops = &drv_ops,
    },
};

static int drvheo_probe(struct platform_device *pdev)
{
    
    
    if (misc_register(&misc[pdev->id]))
        return -EFAULT;

    printk("%s %d, match ok, pdev %d, %s, misc %s %d %d %d\n", __func__, __LINE__,
           pdev->id, pdev->name,
           misc[pdev->id].name, MKDEV(MISC_MAJOR, misc[pdev->id].minor), MISC_MAJOR, misc[pdev->id].minor);

    return 0;
}

static int drvheo_remove(struct platform_device *pdev)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
    misc_deregister(&misc[pdev->id]);
	return 0;
}

static struct platform_device_id tbl[] = {
    
    
    {
    
    "phoenix0"},
    {
    
    "phoenix1"},
    {
    
    },
};

static struct platform_driver drvheo_driver = {
    
    
    .probe = drvheo_probe,
    .remove = drvheo_remove,
    .id_table = tbl,
    .driver = {
    
    
        .name = "phoenix",
    },
};

static int drvheo_init(void)
{
    
    
    printk("%s %d\n", __func__, __LINE__);
	return platform_driver_register(&drvheo_driver);
}

static void drvheo_exit(void)
{
    
    
	printk("%s %d\n", __func__, __LINE__);
    platform_driver_unregister(&drvheo_driver);
    return;
}

module_init(drvheo_init);
module_exit(drvheo_exit);
MODULE_LICENSE("GPL");

打印输出如下:

[root@Hobot msplt] # insmod driver.ko 
drvheo_init 102

[root@Hobot msplt] # insmod dev0.ko
heo_init 37
drvheo_probe 69, match ok, pdev 0, phoenix0, misc phx0 10485793 10 33

[root@Hobot msplt] # cat /dev/phx0 
dmisc_open 15, pdev 10485793 10 33
dmisc_read 25
dmisc_release 20

[root@Hobot msplt] # insmod dev1.ko 
heo_init 37
drvheo_probe 69, match ok, pdev 1, phoenix1, misc phx1 10485792 10 32

[root@Hobot msplt] # cat /dev/phx1  
dmisc_open 15, pdev 10485792 10 32
dmisc_read 25
dmisc_release 20

–end

猜你喜欢

转载自blog.csdn.net/tianzong2019/article/details/124379284
今日推荐