上篇最后的第二种点灯方法年代比较久远,register_chrdev()这个函数一下申请了255个设备号,不建议使用 如下图
下图的函数在linux2.6里是上图函数的升级版,不过他是静态分配,后续还得添加到cdev里
从上图函数不难发现,静态申请多个设备号,主设备号不变,次设备号++
一般我们会使用下图函数动态申请设备号,并添加到cdev里
第一个参数:无符号32位设备号的地址,申请成功后该地址空间里存放的就是设备号
第二个参数:次设备号起始地址,
第三个参数:申请设备号的数量(主设备号不变,次设备号++)
第四个参数:名字(随便给)
申请完设备号后,把它加入cdev链表里
cpp
struct cdev cdev; //定义cdev
struct file_operations led_fops = {
.owner=THIS_MODULE,
.open=led_open,
.release=led_close,
.write=led_write,
};
cdev_init(&cdev, &led_fops); //用文件操作结构体初始化cdev
cdev_add(&cdev, dev, 1); //添加设备号
也可以动态分配
cpp
struct cdev *cdev; //定义cdev
cdev=cdev_alloc();
struct file_operations led_fops = {
.owner=THIS_MODULE,
.open=led_open,
.release=led_close,
.write=led_write,
};
cdev.ops=&fops; //用文件操作结构体初始化cdev
cdev_add(cdev, dev, 1); //添加设备号
这里不需要cdev_init 因为cdev_alloc 跟cdev_init 内操作一样,只是少了一个操作结构体赋值,所以单独补上。
接下里就是创建/dev/led
cpp
struct class *led;
led = class_create(THIS_MODULE, "myled_class");
device_create(led,NULL,dev,NULL,"led");
完整代码
cpp
#include "linux/device.h"
#include "linux/export.h"
#include "linux/gpio.h"
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/init.h"
#include "linux/fs.h"
#include "linux/cdev.h"
#include "linux/uaccess.h"
dev_t dev;
struct cdev cdev;
struct class *led;
static int led_open (struct inode *a, struct file *b){
return 0;
}
static int led_close (struct inode *a, struct file *b){
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
char val;
unsigned long a=copy_from_user(&val,buf,1);
if(a)
{
}
else
{
}
if(val=='1')
{
printk("开灯\r\n");
gpio_set_value(21,1);
gpio_set_value(22,1);
printk("ok\r\n");
}
else
{
printk("关灯\r\n");
gpio_set_value(21,0);
gpio_set_value(22, 0);
printk("ok\r\n");
}
return 0;
}
struct file_operations led_fops = {
.owner=THIS_MODULE,
.open=led_open,
.release=led_close,
.write=led_write,
};
static int __init led_init(void)
{
//申请设备号
int ret= alloc_chrdev_region(&dev,0,1,"led_dev");
if(ret<0)
{
return -1; //加载失败
}
printk(KERN_INFO "LED driver loaded successfully\n");
//初始化LINUX2.6 cdev结构体
cdev_init(&cdev, &led_fops);
cdev_add(&cdev, dev, 1);
gpio_request(21,"led");
gpio_direction_output(21, 0);
gpio_request(22,"led");
gpio_direction_output(22, 0);
led = class_create(THIS_MODULE, "myled_class");
device_create(led,NULL,dev,NULL,"led");
return 0;
}
static void __exit led_exit(void)
{
device_destroy(led, dev);
class_destroy(led);
cdev_del(&cdev);
printk(KERN_INFO "LED driver unloaded successfully\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");