Linux_kernel字符设备驱动12

时间:2024-10-07 07:57:47
        【1】区分主次设备号

设备号(32bit) = 主设备号(12bit [msb])+ 次设备号(20bit [lsb])

                1】示例

        ls -l /dev/tty0

主次设备号的范围理论上都是[0, 255]

主设备号:区分不同类型的设备

次设备号:区分同一类型设备的不同个体

        MINORBITS:次设备号的位数

        MINORMASK:次设备号掩码

        MAJOR(dev):得到主设备号

        MINOR(dev):得到次设备号

        MKDEV(ma,mi):将主设备号与次设备号合为一个32bit整型数(dev_t

        【2】静态注册设备号

                就是自己先挑一个没有被内核占用的设备号去注册

                0】查看被内核占用的设备号

        cat /proc/devices

                1】register_chrdev_region(注册设备号)

注释:

        from:要注册的起始设备号

        count:要连续注册的设备号个数

        name:给设备起的名称

                2】unregister_chrdev_region(注销设备号)

注释:

        from:要注销的起始设备号

        count:要连续注销的设备号个数

        【3】静态注册实验

                1】进入工程目录

        cd /home/zjd/s5p6818/KERNEL/drivers

                2】创建新的工程

        mkdir chrdev

                3】编写程序

        vim chrdev.c

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

#define CHRDEV_MAGOR	200
#define CHRDEV_MINOR	10
#define CHRDEV_NUM		1
#define CHRDEV_NAME		"leds"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int dev = 0;	// store the major dev number and the minor dev number

int __init chrdev_init(void)
{
	int major = CHRDEV_MAGOR;	// major dev number
	int minor = CHRDEV_MINOR;		// minor dev number

	// dev = major << 20 | minor;
	// there is a define func to do this task
	dev = MKDEV(major, minor);

	register_chrdev_region(dev, CHRDEV_NUM, CHRDEV_NAME);	//register the number of device

	return 0;
}

void __exit chrdev_exit(void)
{
	unregister_chrdev_region(dev, CHRDEV_NUM);

	return ;
}

module_init(chrdev_init);
module_exit(chrdev_exit);

                4】编写Makefile

        vim Makefile

obj-m += chrdev.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel
ROOTFS_PATH=/nfs_share/_install

all:
	make -C $(KERNEL_PATH) M=$(PWD) modules
	cp *.ko $(ROOTFS_PATH)

clean:
	make -C $(KERNEL_PATH) M=$(PWD) clean

                5】编译工程

        make

                6】下位机验证

注意:我们现在只有设备号,而没有设备文件

        【4】动态注册设备号

                内核自己找一个没有注册的设备号,注册完归程序员使用

                1】alloc_chrdev_region(注册设备号)

注释:

        dev:回填设备号

        baseminor:次设备号的基值(起始值)

        count:要连续注册的设备号个数

        name:给设备起的名称

                2】unregister_chrdev_region(注销设备号)

注释:

        from:要注销的起始设备号

        count:要连续注销的设备号个数

         【5】动态注册实验

                1】编写程序

        vim chrdev.c

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

#define CHRDEV_MAGOR	200
#define CHRDEV_MINOR	10
#define CHRDEV_NUM		1
#define CHRDEV_NAME		"leds"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int dev = 0;	// store the major dev number and the minor dev number
#if 0
// fixed register
int __init chrdev_init(void)
{
	int major = CHRDEV_MAGOR;	// major dev number
	int minor = CHRDEV_MINOR;		// minor dev number

	// dev = major << 20 | minor;
	// there is a define func to do this task
	dev = MKDEV(major, minor);

	register_chrdev_region(dev, CHRDEV_NUM, CHRDEV_NAME);	//register the number of device

	return 0;
}
#else
// variable register
int __init chrdev_init(void)
{
	int major = CHRDEV_MAGOR;	// major dev number
	int minor = CHRDEV_MINOR;		// minor dev number

	// there is a define func to register the number of devices automatically
	alloc_chrdev_region(&dev, CHRDEV_MINOR, CHRDEV_NUM, CHRDEV_NAME);
	major = MAJOR(dev);	// gain the major dev number
	minor = MINOR(dev);	// gain the minor dev number
	
	printk(KERN_EMERG "dev number is :%d\n major number is :%d\n minor number is :%d\n", dev, major, minor);

	return 0;
}
#endif

void __exit chrdev_exit(void)
{
	unregister_chrdev_region(dev, CHRDEV_NUM);

	return ;
}

module_init(chrdev_init);
module_exit(chrdev_exit);

                2】编写Makefile

        vim Makefile

obj-m += chrdev.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel
ROOTFS_PATH=/nfs_share/_install

all:
	make -C $(KERNEL_PATH) M=$(PWD) modules
	cp *.ko $(ROOTFS_PATH)

clean:
	make -C $(KERNEL_PATH) M=$(PWD) clean

                3】编译工程

        make

                4】下位机验证

注意:我们现在只有设备号,而没有设备文件