标准的字符设备驱动框架
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");
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");
相关文章推荐
- 字符设备驱动编写流程以及大概框架
- 字符设备驱动内核框架小结
- 11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
- linux 字符设备驱动框架
- 字符设备驱动框架1
- Linux字符设备驱动框架
- linux字符设备驱动模板(新标准)
- linux驱动开发之字符设备框架 - 实例
- linux设备驱动--globalmem字符设备框架分析
- Linux驱动(三)字符设备驱动框架
- 内核字符设备驱动框架
- 字符设备驱动基本框架
- linux分类驱动对字符设备框架压力的卸载
- android内核字符驱动设备实战之----------运行时库层jni动态库编程(应该是应用框架层)
- android内核字符驱动设备实战之----------应用框架层aidl服务编程篇
- Driver:模块参数、系统调用、字符设备驱动框架
- linux分类驱动对字符设备框架压力的卸载
- 字符设备驱动框架
- 6410之字符设备驱动的框架
- 韦东山第12课-字符设备驱动框架、led驱动