嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(一)——字符设备驱动

简介: 嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(一)——字符设备驱动

区别于Linux4.0之前的字符设备驱动结构,4.0采用cdev注册字符设备。

一、构造一个字符设备结构体,用于cdev的初始化


struct led_dev_t{
  struct cdev cdev;
};


二、__init 入口函数


1.设备号的处理

dev_t led_devno= MKDEV(led_major,0);


MKDEV(led_major,0)通过主次设备号生成dev_t,在cdev的结构体里面定义了成员dev_t为,32位,12位是主设备号,20位是次设备号。如果不想自己设定主次设备号,可以使用MAJOR(dev_t dev)和MINOR(dev_t dev)生成主次设备号。


if(led_major)
  {
    ret = register_chrdev_region(led_devno, 1,"led");
  }
  else
  {
    ret = alloc_chrdev_region(&led_devno, 0, 1, "led");
    led_major = MAJOR(led_devno);
  }


判断主设备号是否已定义,如果已定义,则注册设备号和设备名;否则申请一个设备号空间然后使用MAJOR(led_devno)生成主设备号。


2.注册字符设备前的准备:申请所需注册设备的结构体空间


ledevp = kzalloc(sizeof(led_dev_t), GFP_KERNEL);  /*申请内存空间*/
  /*判断内存是否申请成功*/
  if(!ledevp)
  {
    ret = -ENOMEM;
    unregister_chrdev_region(led_devno,1);
    return ret;
  }


3.注册字符设备

static void led_setup_cdev(struct led_dev_t *dev,int index)
{
  int err, led_devno = MKDEV(led_major,index);  /*通过主设备号和次设备号生成dev_t*/
  cdev_init(&dev->cdev,&chardev_led_fops);  /*初始化cdev*/
  dev->cdev.owner = THIS_MODULE;
  err = cdev_add(&dev->cdev,led_devno,1);   /*添加一个cdev,param1:cdev,param2:主次设备号*/
  if(err)
  {
    printk(KERN_NOTICE"Error %d adding led %d",err,index);
  }
}


cdev_init初始化cdev,将本驱动的cdev添加进cdev链表


三、字符设备驱动模板


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define LED_MAJOR 229
static int led_major = LED_MAJOR;
/*设备结构体*/
struct led_dev_t{
  struct cdev cdev;
};
struct led_dev_t *ledevp;
static int led_drv_open(struct inode *inode,struct file *file)
{
  /*设置LED引脚为输出模式*/
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
  /*向引脚写入值*/
  copy_from_user(..,buf,..);//从用户空间获得参数
}
const static struct file_operations chardev_led_fops = {
  .owner = THIS_MODULE,
  .open = led_drv_open,
  .write = led_drv_write
};
static void led_setup_cdev(struct led_dev_t *dev,int index)
{
  int err, led_devno = MKDEV(led_major,index);  /*通过主设备号和次设备号生成dev_t*/
  cdev_init(&dev->cdev,&chardev_led_fops);  /*初始化cdev*/
  dev->cdev.owner = THIS_MODULE;
  err = cdev_add(&dev->cdev,led_devno,1);   /*添加一个cdev,param1:cdev,param2:主次设备号*/
  if(err)
  {
    printk(KERN_NOTICE"Error %d adding led %d",err,index);
  }
}
static int __init  chardev_led_init(void)
{
  int ret;
  dev_t led_devno= MKDEV(led_major,0);    
  /*获取字符设备号*/
  if(led_major)
  {
    ret = register_chrdev_region(led_devno, 1,"led");
  }
  else
  {
    ret = alloc_chrdev_region(&led_devno, 0, 1, "led");
  }
  ledevp = kzalloc(sizeof(led_dev_t), GFP_KERNEL);  /*申请内存空间*/
  /*判断内存是否申请成功*/
  if(!ledevp)
  {
    ret = -ENOMEM;
    unregister_chrdev_region(led_devno,1);
    return ret;
  }
  led_setup_cdev(ledevp,1);       /*设置字符设备*/
  return 0;
}
static void __exit chardev_led_exit(void)
{  
  cdev_del(&ledevp->cdev);        /*删除cdev,释放内存空间*/
  kfree(ledevp);
  unregister_chrdev_region(MKDEV(led_major, 0), 1);
}
module_init(chardev_led_init);
module_exit(chardev_led_exit);
MODULE_AUTHOR(" MUGGLE <1198492751@qq.com>")
MODULE_LICENSE("GPL v2");


相关文章
|
3月前
|
存储 缓存 Unix
Linux 设备驱动程序(三)(上)
Linux 设备驱动程序(三)
39 3
|
3月前
|
Linux
Linux 设备驱动程序(四)
Linux 设备驱动程序(四)
24 1
|
3月前
|
存储 数据采集 缓存
Linux 设备驱动程序(三)(中)
Linux 设备驱动程序(三)
37 1
|
2月前
|
Linux API
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
|
3月前
|
存储 缓存 安全
Linux 设备驱动程序(三)(下)
Linux 设备驱动程序(三)
32 0
|
3月前
|
安全 Linux 程序员
Linux 设备驱动程序(二)(下)
Linux 设备驱动程序(二)
27 0
|
2月前
|
Linux 程序员 编译器
Linux内核驱动程序接口 【ChatGPT】
Linux内核驱动程序接口 【ChatGPT】
下一篇
无影云桌面