你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Stm32mp157A-DK1评估Linux LED驱动-2新字符设备

[复制链接]
寒门过河卒 发布时间:2021-6-30 15:19
由上一篇中的字符设备可知我们需要定义设备号,设备号分为主设备号和次设备号,比如上篇中定义的主设备号为200,次设备号为:0。其中主设备号和次设备号必须未被其他设备使用。由ls /dev/ -l可以看到所有的设备号。
新字符设备就是想办法实现动态分配设备号,这样既可以简化操作也可以防止设备号冲突。
打开led.c,首先把设备号,改为设备个数
#define LED_MAJOR             200         
改为#define LED_MAJOR 1 //  设备号个数  
设备名称改为newled
然后需要定义一个字符设备结构体用于设备号的分配:
struct newchrled_dev{
        dev_t devid; /*  设备号 */
        struct cdev cdev; /* cdev */
        struct class *class; /*  类 */
        struct device *device; /*  设备 */
        int major; /* 主设备号 */
        int minor; /* 次设备号 */
};
struct newchrled_dev newchrled; /* led 设备 */
在驱动程序的open中需要加入设备的动态分配结构:
static int led_open(struct inode *inode,struct file *filp)
{
       printk("led_open!\r\n");
       /*在open文件中加入设备动态分配结构体*/
       filp->private_data= &newchrled;
       return0;
}
然后需要修改设备接口程序led_init,在加载设备的时候获取设备号:
原来的程序是
retvalue = register_chrdev(LED_MAJOR,LED_NAME, &led_fops);
直接注册了设备号和设备名称,在现在不知道设备号,所以需要获取设备号然后再创建设备,其步骤为:
获取设备号-》初始化设备-》加载设备号-》创建设备类-》创建设备
1、  获取设备号,新字符设备在结构体中也可以自己设置设备号,如果自己设置则把自己设置的设备号加载进去,如果未设置设备号则alloc_chrdev_region自动获取并且加载:
if (newchrled.major) { // 如果定义了设备号
         newchrled.devid =MKDEV(newchrled.major, 0); //获取定义的设备号
         ret =register_chrdev_region(newchrled.devid, LED_MAJOR,LED_NAME); //注册已定义的设备号、设备个数、设备名
         if(ret < 0) {
                pr_err("cannotregister %s char driver [ret=%d]\n",LED_NAME, LED_MAJOR);
                goto fail_map;
                }
  } else { // 如果没有定义设备号
         ret =alloc_chrdev_region(&newchrled.devid, 0, LED_MAJOR,LED_NAME);  //申请设备号并且注册设备号、设备个数、设备名
         if(ret < 0) {
                pr_err("%sCouldn't alloc_chrdev_region, ret=%d\r\n",
                LED_NAME, ret);
                goto fail_map;
         }
         newchrled.major =MAJOR(newchrled.devid); // 获取主设备号
         newchrled.minor =MINOR(newchrled.devid); // 获取次设备号
}
2、  设备号定义后需要把设备结构体和设备驱动关联起来,此处需要对newchrled进行初始化:
newchrled.cdev.owner = THIS_MODULE; //定义设备结构体的owner 默认设置为THIS_MODULE
cdev_init(&newchrled.cdev,&led_fops); //初始化设备结构体关联到led_fops驱动接口
3、  需要在初始化后的设备结构体中添加以获取的设备号:
ret = cdev_add(&newchrled.cdev, newchrled.devid, LED_MAJOR);
if(ret < 0)
goto del_unregister;
4、  接下来把设备名写入设备结构体,创建为一个设备类:
newchrled.class = class_create(THIS_MODULE, LED_NAME);
if (IS_ERR(newchrled.class)) {
  goto del_cdev;
}
5、  最后创建设备:
newchrled.device = device_create(newchrled.class, NULL,newchrled.devid,NULL, LED_NAME);
  if (IS_ERR(newchrled.device)) {
  goto destroy_class;
}
如果中间有错误,则清除对应的操纵并推出函数:
, t! g- b9 Z0 X+ h/ S" T5 o
destroy_class:
  class_destroy(newchrled.class);//删除类
del_cdev:
  cdev_del(&newchrled.cdev); //删除设备号
del_unregister:
  unregister_chrdev_region(newchrled.devid,LED_MAJOR);//删除设备关联
fail_map:
  /* 取消映射 */
  iounmap(MPU_AHB4_PERIPH_RCC_PI);
  iounmap(GPIOI_MODER_PI);
  iounmap(GPIOI_OTYPER_PI);
  iounmap(GPIOI_OSPEEDR_PI);
  iounmap(GPIOI_PUPDR_PI);
  iounmap(GPIOI_BSRR_PI);
return -EIO;

2 k) ~5 l) A! _3 Y6 x7 C8 o& D3 {% t" S
在卸载驱动接口中也需要加入设备号、设备类、设备关联状态的清除:
//卸载驱动
static void __exit led_exit(void)
{
  printk("led_exit!\r\n");
  /* 取消映射 */
  iounmap(MPU_AHB4_PERIPH_RCC_PI);
  iounmap(GPIOI_MODER_PI);
  iounmap(GPIOI_OTYPER_PI);
  iounmap(GPIOI_OSPEEDR_PI);
  iounmap(GPIOI_PUPDR_PI);
  iounmap(GPIOI_BSRR_PI);
) X: _% h6 w7 c6 Z' o( e, _0 D
  cdev_del(&newchrled.cdev); //删除设备号     
  unregister_chrdev(LED_MAJOR,LED_NAME);/* 注销字符设备驱动 */
; X2 d5 b. |& l6 y( J/ F
  unregister_chrdev_region(newchrled.devid,LED_MAJOR);//删除设备关联
  class_destroy(newchrled.class);//删除类

) Y$ R) J7 Y* @3 z% K: d
}
到此程序编写完毕,开始测试:
newchrdevbase.rar (33.74 KB, 下载次数: 0)
收藏 评论0 发布时间:2021-6-30 15:19

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版