您的位置:首页 > 运维架构 > Linux

标准的字符设备驱动框架

2017-08-24 11:04 225 查看
标准的字符设备驱动可以分为以下几个步骤:

1.构建模块程序的架构

2.申请字符设备的设备号:静态申请和动态申请

3.创建一设备结构 注册到内核

4.填充file_operations 结构体,实现驱动的相关操作(核心)

5.创建设备类 /sys/class/

6.创建设备结构体 注册设备文件节点 /dev/xxx 为应用程序的调用提供接口

步骤的详细的讲解:

1.构建模块程序的架构 头文件#include <linux/nodule.h>

  模块的入口函数  module_init()

  模块的出口函数  module_exit()

  模块的遵循协议 

      MODULE_LICENSE("Dual BSD/GPL");

      MODULE_AUTHOR("XXXX");

      MODULE_DESCRIPTION("xxx");
 
 

2.注册设备号 #include< linux/fs.h>

  静态注册 int register_chrdev_region(dev_t from, unsigned count, const char *name)

  1.from:设备号                   2.count:申请设备的个数

    name:名称                      
成功时返回 0 否则为 -1

  2. int mjor = MAJOR(dev_t dev);  返回主设备号

     int minor =MINOR(dev_t dev);  返回次设备号

     dev_t dev = MKDEV(ma,mi);     通过主次设备号求取设备号
头文件 #include <linux/kdev_t.h>

  动态注册设备号:头文件 #include <linux/fs.h>

  1.int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)

    dev :主设备号的地址 
baseminor :第一个设备的此设备号
count :申请的个数
name :与设备号绑定的相应名称

成功返回 零 否则 -1
且返回分配的设备号在dev的地址处

  注销设备号

   1. void unregister_chrdev_region(dev_t from, unsigned count)

    dev_t from:设备号   

    unsigned count :设备的申请个数

3.分配cdev结构 并且注册到内核

 1.相关的头文件   

  #include <linux/kobject.h>

  #include <linux/kdev_t.h>

  #include <linux/list.h>

 2.实现驱动时需要填充的结构体

  struct file_operations;

 3.结构cdev
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};

  4.初始化结构体

    void cdev_init(struct cdev *, const struct file_operations *);

  5.动态分配一个结构体 在堆区中

    struct cdev *cdev_alloc(void);

  6.将结构体cdev填充到内核

    int cdev_add(struct cdev *, dev_t, unsigned);

  7.注销内核中的设备结构体类

    void cdev_del(struct cdev *);

4.申明一个设备类,并且注册设备文件节点 

  1.创建设备类  struct class *class_create(owner, name)

    owner:THIS_MODULE

    name :设备类的名称

   返回设备类的指针

  

  2.创建一个设备 并且申明设备文件节点的名称

   struct device *device_create(struct class *class, struct device *parent,
    dev_t devt, void *drvdata, const char *fmt)

     

    class : class_create 返回的指针
parent:NULL

    devt :设备号
drvdata:NULL
fmt :/dev/fmt 设备文件节点的名称
返回 device 的指针 否者NULL

 3.销毁一个设备和注销设备文件节点

   void device_destroy(struct class *class, dev_t devt)

   class :class_create 返回的指针

   devt :设备号

 

 4.摧毁一个设备类

   void class_destroy(struct class *cls)

   cls:class_create 返回的指针

实例代码

#include <linux/init.h>

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/stat.h>

#include <linux/fs.h>

#include <linux/kdev_t.h>

#include <linux/cdev.h>

#include <linux/slab.h>

#include <linux/device.h>  

//led操作相关的函数

#include <linux/gpio.h>

#include <plat/gpio-cfg.h>

#include <mach/gpio-exynos4.h>

dev_t dev_num=0;

int major=200;

int minor=0;

int ret =0;

static struct class *my_class;

static struct device *my_device;

static struct cdev led_dev;

static int led_drv_open(struct inode *inode, struct file *file)

{
printk(KERN_EMERG "led_drv_open is success!\n");
printk(KERN_EMERG "led_drv_open is init GPIO success!\n");
return 0;

}

static int led_drv_release(struct inode *inode, struct file *file)

{
printk(KERN_EMERG "led_drv_release is success!\n");

return 0;

}

static long led_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{
switch(cmd)
{
case 0:
case 1:
gpio_set_value(EXYNOS4_GPK1(1), cmd);
break;

default:
return -EINVAL;
}
printk(KERN_EMERG"GPIIOK1 1 operate sucessfully\n");
return 0;

}

ssize_t led_drv_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops)

{
return 0;

}

ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *f_ops)

{

return 0;

}

loff_t led_drv_llseek(struct file *file, loff_t offset, int ence)

{
return 0
4000
;

}

 struct file_operations led_fops ={
.owner=THIS_MODULE,
.open = led_drv_open,
.release = led_drv_release,
.unlocked_ioctl = led_drv_ioctl,
.read = led_drv_read,
.write = led_drv_write,
.llseek = led_drv_llseek,

 };

 

static int gpio_init(void)

{
ret = gpio_request(EXYNOS4_GPK1(1), "led");
if (ret)
{
 printk("request GPIO for LED failed\n");
 return ret;
}
else
{
s3c_gpio_cfgpin(EXYNOS4_GPK1(1), S3C_GPIO_OUTPUT);
gpio_set_value(EXYNOS4_GPK1(1), 1);

}
return 0;

}

 

static int led_driver_init(void)

{

#ifdef DE_BUG

   printk("hello word,i'm coming the module\n");

   printk("start registry device number\n");

#endif

    ret = gpio_init();
if(ret){
printk(KERN_EMERG "gpio_init failed!\n");
}

  

   if(major)

   {
   dev_num = MKDEV(major,minor);
   ret = register_chrdev_region(dev_num,1,DRIVER_NAME);
if(ret < 0)
{
printk("start registry device number faild\n");
printk("start registry device number faild\n");
return -1;
}

   }

   else

   {
   ret = alloc_chrdev_region(&dev_num,minor,1,DRIVER_NAME);
if(ret < 0)
{
printk("start registry device number faild\n");
printk("start registry device number faild\n");
return -1;
}
major = MAJOR(dev_num);
minor = MINOR(dev_num);
printk("the character deriver's major = %d minor = %d\n",major,minor);

   }

#ifdef DE_BUG

   printk("registry device number is  ok\n");

   printk("The device structure is registered with the kernel\n");

#endif  

   

   cdev_init(&led_dev,&led_fops);

   led_dev.owner = THIS_MODULE;

   led_dev.ops =&led_fops;

   ret = cdev_add(&led_dev,dev_num,1);

   if(ret < 0)

   {
printk("The device structure is registered with the kernel is faild\n");  
goto faild1;

   }

   

#ifdef DE_BUG

   printk("The device structure is registered with the kernel is ok\n");

   printk("We start creating the device class\n");

#endif  

   

   my_class=class_create(THIS_MODULE,DRIVER_CLASS);

   if(!my_class)

   {
 printk("We creating the device class faild\n");
 goto faild2;

   }

#ifdef DE_BUG

   printk("We  creating the device class is sucess\n");

   printk("Let's start registering file device nodes\n");

#endif  

   

  my_device=device_create(my_class,NULL,dev_num,NULL,DR_DEV_NAME);

  if(!my_device)

  {
printk("Let's start registering file device nodes is faild\n"); 

     goto faild3;  

  }

  printk(KERN_EMERG "led_driver_init sucess!\n");

 

   return 0;

   

faild3:

   class_destroy(my_class);

faild2:

   cdev_del(&led_dev);

faild1:

   unregister_chrdev_region(dev_num,1);

   return -1;

}

static void led_driver_exit(void)

{

  gpio_free(EXYNOS4_GPK1(1));

  printk(KERN_EMERG "GPIOK1 1 free is success!\n");

  class_destroy(my_class);

  cdev_del(&led_dev);

  unregister_chrdev_region(dev_num,1);

  printk("good byte module\n");

}

module_init(led_driver_init);

module_exit(led_driver_exit);

MODULE_AUTHOR("LUO LEI");

MODULE_LICENSE("Dual BSD/GPL");   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息