十四、(正点原子)Linux MISC驱动

        misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动。

一、MISC设备驱动

        随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号。所以在MISC驱动中所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。
        MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。

        在MISC中,使用struct miscdevice结构体来表示一个设备,我们需要向 Linux 注册一个 struct miscdevice 设备,内容如下:

定义在文件 include/linux/miscdevice.h 中

struct miscdevice  {
	int minor;                             /* 次设备号 */
	const char *name;                      /* MISC设备名字 */
	const struct file_operations *fops;    /* 设备操作集合 */
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const struct attribute_group **groups;
	const char *nodename;
	umode_t mode;
};

         定义一个 MISC 设备(struct miscdevice 类型)以后我们需要设置 minorname fops 这三个成员变量。 minor 表示子设备号, MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备号, Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号如下所示:

定义在include/linux/miscdevice.h 文件中

#define PSMOUSE_MINOR		    1
#define MS_BUSMOUSE_MINOR	    2	    /* unused */
#define ATIXL_BUSMOUSE_MINOR	3	    /* unused */

/*#define AMIGAMOUSE_MINOR	    4	    FIXME OBSOLETE */

#define ATARIMOUSE_MINOR	    5	    /* unused */
#define SUN_MOUSE_MINOR		    6	    /* unused */
#define APOLLO_MOUSE_MINOR	    7	    /* unused */
#define PC110PAD_MINOR		    9	    /* unused */

/*#define ADB_MOUSE_MINOR	    10	FIXME OBSOLETE */

#define WATCHDOG_MINOR		    130	    /* Watchdog timer     */
#define TEMP_MINOR		        131	    /* Temperature Sensor */
#define RTC_MINOR		        135
#define EFI_RTC_MINOR		    136	    /* EFI Time services */
#define VHCI_MINOR		        137
#define SUN_OPENPROM_MINOR	    139
#define DMAPI_MINOR		        140	    /* unused */
#define NVRAM_MINOR		        144
#define SGI_MMTIMER		        153
#define STORE_QUEUE_MINOR	    155	    /* unused */
#define I2O_MINOR		        166
。。。
#define MISC_DYNAMIC_MINOR	    255    /* 动态自己分配 */

        我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。当设置为255时,内核自动动态分配次设备号。

        name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。 fops 就是字符设备的操作集合, MISC 设备驱动最终是需要使用用户提供的 fops操作集合。

        当设置好 struct miscdevice 以后就需要使用 misc_register 函数向系统中注册一个 MISC 设备,此函数原型如下:

定义在include/linux/miscdevice.h 文件中

extern int misc_register(struct miscdevice *misc);

        misc:要注册的MISC设备。 

        返回值:负数,失败;0,成功。

        以前创建字符设备时,需要调用一堆的函数去注册设备号,初始化字符设备,添加字符设备等等步骤如下所示:

传统的创建设备过程

alloc_chrdev_region();       /* 申请设备号 */
cdev_init();                 /* 初始化 cdev */
cdev_add();                  /* 添加 cdev */
class_create();              /* 创建类 */
device_create();             /* 创建设备 */

        但是在MISC设备驱动中,其实也是一个字符设备,使用misc_register 函数就能够自动完成以前字符设备创建的功能。同理,在注销字符设备时候我们也需要调用一堆函数将前面创建的一些结构体给释放掉比如:


/* 注销设备号 */
unregister_chrdev_region(dtsled.devid, DTSLED_CNT);

/* 注销LED字符设备 */
cdev_del(&dtsled.cdev);
 
/* 删除设备 */
device_destroy(dtsled.class, dtsled.devid);
 
/* 删除类 */
class_destroy(dtsled.class);

        当我们使用的时MISC设备时,就只需要调用 misc_deregister 函数就可以注销设备驱动,函数原型如下:

定义在include/linux/miscdevice.h 文件中

extern int misc_deregister(struct miscdevice *misc);

        misc:要注销的MISC设备。

        返回值:负数,失败;0,成功。

二、MISC设备驱动示例代码

        


/* 设备操作函数 */
struct file_operations xxx_fops = {
    .owner = THIS_MODULE,
};

/* MISC 设备结构体 */
struct miscdevice xxx_miscdev = {
    .minor = 255,    /* 前面有定义 */
    .name = "xxx",
    .fops = &xxx_fops,
};

/* flatform 驱动的 probe 函数,当驱动与设备匹配以后此函数就会执行 */
int xxx_probe(struct platform_device *dev)
{
    。。。。
    misc_register(&xxx_miscdev);
    return 0;
}


/* remove函数,移除 platform 驱动的时候此函数会执行 */
int xxx_remove(struct platform_device *dev)
{
    。。。
     /* 注销 misc 设备驱动 */
    misc_deregister(&xxx_miscdev);
    return 0;
}

/* 匹配列表 */
const struct of_device_id beep_of_match[] = {
    { .compatible = "xxx" },     /* 要与设备树的compatible属性一致 */
    { /* Sentinel */ }
};

/* 驱动设备结构体 */
struct platform_driver xxx_driver = {
    .driver = {
        .name = "xxx",                  /* 驱动名字 */
        .of_match_table = xxx_of_match,  /* 设备树匹配表 */
    },
    .probe = xxx_probe,
    .remove = xxx_remove,

};

/* 驱动入口函数 */
static int __init xxx_init(void)
{
    return platform_driver_register(&xxx_driver);
}


 /* 驱动出口函数 */
static void __exit xxx_exit(void)
{
    platform_driver_unregister(&xxx_driver);
}

module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhangxueguo");

        当我们驱动加载成功后,在/sys/class/misc这个目录下可以看到一个struct platform_driver->driver->name名字的设备,如果MISC设备与驱动像匹配以后,就会在dev/下生成的一个struct miscdevice->name设备驱动文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tofu_Cabbage

你的打赏是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值