[linux驱动开发] platform总线驱动使用misc注册方式

解析设备树信息

设备树编辑和解析方式在我另外一篇基于gpiod API的platform总线多个led驱动开发

misc设备简介

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

  • 注册结构体的定义在文件 include/linux/miscdevice.h
struct miscdevice  {
    int minor;
    const char *name;
    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 设备(miscdevice 类型)以后我们需要设置 minor、 name 和 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 APM_MINOR_DEV		134
#define RTC_MINOR		135
/*#define EFI_RTC_MINOR		136	was EFI Time services */
#define VHCI_MINOR		137
#define SUN_OPENPROM_MINOR	139
#define DMAPI_MINOR		140	/* unused */
#define NVRAM_MINOR		144
#define SBUS_FLASH_MINOR	152
.....

注册卸载函数

//注册函数
extern int misc_register(struct miscdevice *misc);
//卸载函数
extern void misc_deregister(struct miscdevice *misc);

注册函数可以替代之前所做的事情,如下

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

卸载函数同理

注册函数和misc_open函数详解

查看注册函数的解释
在这里插入图片描述
意思是在系统调用open时候,file->pricate_data会指向该结构体,即struct miscdevice结构体。
该操作的所在位置。

  • 查看misc_open函数的操作,
    在这里插入图片描述
    简单讲解这个操作的含义,最终结果 文件指针,file指针的私有数据区存放,自己定义misc结构体指针。
  • 重点来了,在misc结构体中除了前三个变量需要自己定义,后面几个也需要关注,其中的
    struct device *this_device;

该结构体指向misc设备的设备指针,当然它也有私有数据区,就可以利用该区进行私有数据保存,因为misc设备时全局变量。

数据流向:

  1. 在probe中初始化相关IO状态后,保存私有数据地址
  2. misc注册成功后,给misc设备的this_device成员保存该私有数据地址priv_data
  3. 在自定义 open 或者 在其他接口函数中 取出file-private_data ,数据类型为miscdevice
  4. 取出该设备中的私有数据 priv_data = drv_get_drvdata(miscdevice->this_device),就可以使用该私有变量中的数据

基于misc设备注册的代码

probe部分

//1.初始化io状态
    rv = paser_dt_init_led(pdev);
    if(rv < 0)
    {
        return rv;
    }
    priv = platform_get_drvdata(pdev); //获取私有数据

    //2.注册misc设备
    rv = misc_register(&led0_miscdev);
    if(rv < 0)
    {
        dev_err(&pdev->dev,"misc led0 device register failure.\n");
        return -EFAULT;
    }
    dev_set_drvdata(led0_miscdev.this_device, priv); //将私有数据保存至misc设备的私有数据区

    //第二个设备注册
    rv = misc_register(&led1_miscdev);
    if(rv < 0)
    {
        dev_err(&pdev->dev,"misc led1 device register failure.\n");
        return -EFAULT;
    }
    dev_set_drvdata(led1_miscdev.this_device, priv);

    printk("misc gpio leds driver probe okay.\n");

remove部分

	for(i=0; i<priv->num_leds; i++)
	{
	    gpiod_set_value(priv->leds[i].led_gpiod, OFF);
	    devm_gpiod_put(&pdev->dev, priv->leds[i].led_gpiod); //释放gpiod
	}
	
	//注销misc设备
	misc_deregister(&led0_miscdev);
	misc_deregister(&led1_miscdev);
	
	printk("misc gpio leds driver remove.\n");

fops接口

ioctl接口

	miscdev = filp->private_data; //open misc设备时候,miscdevice放到该私有数据处
    priv = dev_get_drvdata(miscdev->this_device);
 
    switch (cmd) {
        case LED_OFF:/* variable case */
            if(priv->num_leds <= arg)
            {
                printk("led%ld doesn't exist\n", arg);
                return -ENOTTY;
            }
            gpiod_set_value(priv->leds[arg].led_gpiod, OFF);
            break;
        case LED_ON:
            if(priv->num_leds <= arg)
            {
                printk("led%ld doesn't exist\n", arg);
                return -ENOTTY;
            }
            gpiod_set_value(priv->leds[arg].led_gpiod, ON);
            break;
        default:
            printk("driver don't support ioctl command=%d\n", cmd);
            print_led_help();
    }   

其他函数操作看我的另一篇博客 基于gpiod API的platform总线多个led驱动开发

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值