一、linux2.6开发
1.1 linux2.6和杂项的区别
杂项:
驱动程序注册的一种方式,主设备号不用申请固定是10,次设备号0-255,固定填255 自动分配次设备号。杂项注册完成之后他会自动的在/dev/目录下生成一个设备文件,一台设备最多只能挂载256个杂项设备。
linux2.6:
在linux2.6设备注册完成之后不会自动的生成设备文件,可以手工生成设备文件
mknod /dev/myled c 5 3
也可以借助于自动生成设备文件相关函数,主设备号和次设备号是没有限制,主设备号总共可用的有 2^12个,次设备号总共可用的有 2^20个。由于主设备和次设备号都是没有限制的,就有可能跟现有的设备号冲突,为了避免这种情况发生最好不要自己指定主次设备号,要去找系统分配。
1.2 linux2.6申请设备号
函数的功能:
向内核申请一个可用的设备号
函数的头文件:
linux/fs.h
函数的原型:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
函数的参数:
dev_t *dev, 存放设备号的指针
unsigned baseminor, 次设备号的起始值 一般填0
unsigned count, 要申请的设备号的个数
const char *name 名字 设备号的名字
函数的返回值:
成功返回 0
失败返回 非零
MINOR(dev) 获取次设备号
MAJOR(dev) 获取主设备号
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
释放设备号
函数的原型:
void unregister_chrdev_region(dev_t from, unsigned count)
函数的参数:
dev_t from, 设备号的起始位置
unsigned count 要释放的设备号的个数
函数的返回值:
无
1.3 linux2.6注册相关API
关键字 cdev
头文件:
linux/cdev.h
函数:
cdev_init 初始化
cdev_add 注册
cdev_del 删除
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
初始化linux2.6的核心结构体
函数的原型:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
函数的参数:
struct cdev *cdev, linux2.6核心结构体
const struct file_operations *fops 操作集合结构体
函数的返回值:
无
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
向内核注册一个linux2.6的内核
函数的原型:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
函数的参数:
struct cdev *p, linux2.6的核心结构体的指针
dev_t dev, 设备号
unsigned count 要注册的个数
函数的返回值:
成功返回 0
失败返回 负数
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
删除linux2.6设备的注册
函数的原型:
void cdev_del(struct cdev *p)
函数的参数:
struct cdev *p:linux2.6的核心结构体
函数的返回值:
无
1.4 linux2.6自动生成设备文件相关API
linux2.6设备注册的时候优点是可以使用的设备号的范围很广,有一个最大的缺点就是不能自动的生成设备文件。
第一种:手动执行命令来生成设备文件mknod,这种方法比较繁琐 不方便
第二种:借助于内核提供的自动生成设备文件的api,要想使用自动生成设备文件的api ,就必须要有一个类结构体。
函数的功能:
创建类结构体
函数的头文件:
linux/device.h
函数的原型
#define class_create(owner, name)
({
static struct lock_class_key __key;
__class_create(owner, name, &__key);
})
可以理解成:
struct class * class_create(struct module *owner, const char *name)
函数的参数:
struct module *owner, 固定填写 THIS_MODULE
const char *name 类的名字 随意填写 最好有点意义
函数的返回值:
成功返回 类结构体的指针
失败返回 NULL
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
自动的创建一个设备文件
函数的头文件:
linux/device.h
函数的原型:
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
函数的参数:
struct class *class, 类结构体的指针
struct device *parent, 父节点设备 填NULL
dev_t devt, 设备号
void *drvdata, 传递给设备的私有数据 NULL
const char *fmt, ... 可变的传参 一般写设备的名字
函数的返回值:
成功返回 设备的结构体指针
失败返回 NULL
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
销毁设备
函数的头文件:
linux/device.h
函数的原型:
void device_destroy(struct class *class, dev_t devt)
函数的参数:
struct class *class:类结构体指针
dev_t devt :设备号
函数的返回值:
无
+++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:
销毁类结构体
函数的头文件:
linux/device.h
函数的原型:
void class_destroy(struct class *cls)‘
函数的参数:
struct class *cls:类结构体指针
函数的返回值:
无
1.5 linux2.6设备注册示例
mylinux.c文件
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>
struct file_operations myfops;
struct cdev mycdev;
struct class *myclass;
dev_t mydev;
int myopen(struct inode *inode, struct file *file){
gpio_set_value(EXYNOS4X12_GPM4(0),1);
printk("LED4\n");
return 0;
}
int myclose(){
gpio_set_value(EXYNOS4X12_GPM4(0),1);
gpio_direction_output(EXYNOS4_GPD0(0), 0);
printk("close\n");
return 0;
}
static int __init myled_init(void){
if(alloc_chrdev_region(&mydev,0,1,"myBP")<0){
printk("alloc_chrdev_region error\n");
}
printk("设备号:%d\n",mydev);
printk("主设备号:%d\n",MAJOR(mydev));
printk("次设备号:%d\n",MINOR(mydev));
myfops.owner=THIS_MODULE;
myfops.open=myopen;
myfops.release=myclose;
cdev_init(&mycdev,&myfops);
cdev_add(&mycdev,mydev,1);
myclass=class_create(THIS_MODULE,"myBP");
if(myclass==NULL){
printk("创建class失败\n");
return -1;
}
device_create(myclass,NULL,mydev,NULL,"myBP");
if(gpio_set_value(EXYNOS4_GPD0(0),"test")<0){
printk("GPIO申请失败\n");
}
gpio_direction_output(EXYNOS4_GPD0(0), 0);
return 0;
}
static void __exit myled_exit(void){
//销毁类
device_destroy(myclass,mydev);
//销毁类结构体
class_destroy(myclass);
//释放linux2.6的注册
cdev_del(&mycdev);
//释放设备号
unregister_chrdev_region(mydev,0);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");