目录
1.Linux2.6开发特点:
2.Linux2.6开发流程
3.Linux2.6开发的相关接口函数
·alloc_chrdev_region()申请设备号函数
·unregister_chrdev_region()释放设备号函数
·初始化cdev结构体
·注册cdev设备
·删除注册的cdev结构体
4.生成设备文件的指令和接口
1.手动创建设备文件:
2.利用函数生成:生成类结构体->利用类结构体生成设备文件
·生成类结构体函数
·摧毁类结构体函数
·生成设备文件的函数
·销毁设备文件的函数
5.基于Linux2.6开发驱动led灯闪烁
1.Linux2.6开发特点:
- 标准化。可以清晰明了地了解开发代码的操作。
- 设备范围广泛。不限制设备号,开发时需要自己申请设备号。
- 注册完毕后不会生成设备文件。需要用指令生成或内核其他接口生成。
2.Linux2.6开发流程
驱动注册->分配cdev设备号(静态分配register_chrdev_region/动态分配alloc_chrdev_region)->初始化cdev(cdev_init)->注册cdev(cdev_add)->初始化硬件->设备操作函数的实现(open/read/write/close)->驱动注销(cdev_del/unregister_chrdev_region)
3.Linux2.6开发的相关接口函数
·alloc_chrdev_region()申请设备号函数
函数功能:向内核申请一个可以使用的设备号(连续申请)
函数头文件:<linux/fs.h>
函数原型:
int alloc_chrdev_region(dev_t * devnum, unsigned base_minor, unsigned count, const char * labelname
);
函数参数:
devnum:设备号。需要提供一个这样类型的空间。函数申请设备号成功,就会把申请得到的首设备号存入该空间。
base_minor:起始次设备号。跟系统指定准备从哪个次设备号开始使用。
count:要申请的设备号数量。
label_name:给它们的名字
函数返回值:成功返回0
·unregister_chrdev_region()释放设备号函数
函数功能:释放申请得到的设备号
函数头文件:<linux/fs.h>
函数原型:
void unregister_chrdev_region(dev_t devnum, unsigned count
);
函数参数:
devnum:申请得到的首设备号
count:连续释放的数量
函数返回值:无
·初始化cdev结构体
函数功能:初始化一个cdev结构体
函数头文件:<linux/cdev.h>
函数原型:
void cdev_init(struct cdev * cdevp, const struct file_operations * fops
);
函数参数:
cdevp:给函数一个cdev结构体空间。
fops:提供一个ops结构体,并至少填入其中的owner、open、release。
函数返回值:无
·注册cdev设备
函数功能:向内核注册一个cdev结构体。可以一次注册多个设备。
函数原型:
int cdev_add(struct cdev * cdevp, dev_t dev_num, unsigned count
);
函数参数:
cdevp:填入经cdev_init初始化完毕的结构体
dev_num:经过alloc_chrdev_region申请的设备号
count:要注册的设备数量
函数返回值:成功返回0
·删除注册的cdev结构体
函数功能:从内核取消一个cdev的结构体的注册
函数原型:
void cdev_del(struct cdev * cdevp);
函数参数:cdevp:传入cdev结构体,即可自动取消全部设备的注册
函数返回值:无
4.生成设备文件的指令和接口
1.手动创建设备文件:
mknod /dev/xxx c 主设备号 次设备号
2.利用函数生成:生成类结构体->利用类结构体生成设备文件
·生成类结构体函数
struct class * class_create(owner , name);
其中,owner固定填写,name可任意命名。
·摧毁类结构体函数
void class_destroy(struct class *cls);
·生成设备文件的函数
struct device *device_create(struct class *cls, //类结构体struct device *parent,//父设备dev_t devt, //设备号void *drvdata, //设备的私有数据const char *fmt, ...//格式化设备名
);
·销毁设备文件的函数
void device_destroy(struct class *cls, dev_t devt
);
5.基于Linux2.6开发驱动led灯闪烁
驱动开发程序
此处led1的引脚为gpio的第24个引脚,低电平亮
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/miscdevice.h"
#include "linux/gpio.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/device.h"
dev_t devnum;
struct cdev cdevp;
struct file_operations ops;
struct class * cls;
int led1_open (struct inode * a, struct file * b){gpio_set_value(24,0);return 0;
}
int led1_close (struct inode * c, struct file * d){gpio_set_value(24,1);return 0;
}//加载函数->驱动入口
static int __init test_init(void)
{gpio_request(24,"myled1");gpio_direction_output(24,1);//1.先申请一个设备号alloc_chrdev_region(&devnum,78,1,"led1_dev");printk("主设备号 == %d\r\n",devnum >> 20);printk("次设备号 == %d\r\n",devnum &0xFFFFF);//2.初始化cdev结构体ops.owner = THIS_MODULE;ops.open = led1_open;ops.release = led1_close;cdev_init(&cdevp,&ops);//3.注册cdev到内核cdev_add(&cdevp,devnum,1);cls = class_create(THIS_MODULE,"led1_devclass");device_create(cls,NULL,devnum,NULL,"LED1_test07");return 0;
}
//卸载函数->驱动的出口
static void __exit test_exit(void)
{printk("hello 出口函数!\r\n");device_destroy(cls, devnum);class_destroy(cls);//注销cdev设备cdev_del(&cdevp);//释放申请的设备号unregister_chrdev_region(devnum,1);//释放gpio引脚gpio_free(24);
}
//内核层的声明
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");//必须遵循开源协议
应用层程序--控制led1闪烁
#include "stdio.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/types.h"
#include "sys/stat.h"
int main(){int fd1 = 0;while(1){ fd1 = open("/dev/LED1_test07",O_RDONLY);sleep(1);close(fd1);sleep(1);}
}
开发板下执行注册、注销和执行程序操作
其中打印了字符设备的主设备号和次设备号,可以通过查看日志信息指令获取。