注意
字符设备文件本身代表的就是字符设备硬件本身
字符设备文件存在于根文件系统必要目录的dev目录下 ,当然块设备文件也存于dev目录下
例如:查看板子上UART设备的字符设备文件:
ls /dev/ttySAC* -lh 得到以下信息:
crw-rw---- 204, 64 /dev/ttySAC0
crw-rw---- 204, 65 /dev/ttySAC1
crw-rw---- 204, 66 /dev/ttySAC2
crw-rw---- 204, 67 /dev/ttySAC3
mknod /dev/(字符设备文件名) c 主设备号 次设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
参数:
设备驱动一旦不再使用设备号,记得要将设备号资源归还给linux内核:
释放申请的设备号资源函数
void unregister_chrdev_region(dev_t dev, unsigned count);
//描述字符设备驱动给用户提供的操作接口
struct file_operations {int (*open) (struct inode *, struct file *); //给用户提供打开设备的接口int (*release) (struct inode *, struct file *); //给用户提供关闭设备的接口...
};
//描述字符设备驱动
struct cdev {dev_t dev; //描述申请的设备号int count; //描述申请的次设备号的个数struct file_operations *ops;//给用户提供的操作接口...};
cdev_init(strcut cdev *cdev, struct file_operations *fops)
cdev_add(struct cdev *cdev, dev_t dev, int count)
cdev_del(struct cdev *cdev)
struct file_operations led_fops = {.open = led_open, //打开设备接口.release = led_close, //关闭设备接口};
struct cdev led_cdev; //定义字符设备对象
//led_cdev.ops = &led_fops
cdev_init(&led_cdev, &led_fops);//给字符设备对象添加硬件操作接口
cdev_del(&led_cdev);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <linux/cdev.h> //strcut cdev
#include <linux/fs.h> //struct file_operations//声明描述LED硬件信息相关的数据结构
struct led_resource {int gpio; //GPIO软件编号char *name;//LED的名称
};//定义初始化四个LED灯的硬件信息对象
static struct led_resource led_info[] = {{.name = "LED1",.gpio = PAD_GPIO_C+12},{.name = "LED2",.gpio = PAD_GPIO_C+7},{.name = "LED3",.gpio = PAD_GPIO_C+11},{.name = "LED4",.gpio = PAD_GPIO_B+26}
};//定义设备号对象
static dev_t dev;//定义字符设备对象
static struct cdev led_cdev;//打开设备操作接口
//调用关系:应用open->软中断->内核的sys_open->驱动的led_open
int led_open(struct inode *inode, struct file *file)
{//1.开灯int i;for(i = 0; i < ARRAY_SIZE(led_info); i++) {gpio_set_value(led_info[i].gpio, 0);}printk("%sn", __func__);return 0; //执行成功返回0,执行失败返回负值
}//关闭设备操作接口
//调用关系:应用close->软中断->内核的sys_close->驱动的led_close
int led_close(struct inode *inode, struct file *file)
{//1.关灯int i;for(i = 0; i < ARRAY_SIZE(led_info); i++) {gpio_set_value(led_info[i].gpio, 1);}printk("%sn", __func__);return 0; //执行成功返回0,执行失败返回负值
}//定义初始化LED的硬件操作接口对象
static struct file_operations led_fops = {.open = led_open, //打开设备接口.release = led_close //关闭设备接口
};static int led_init(void)
{int i;//1.申请GPIO资源,配置GPIO为输出,输出1(省电)for (i = 0; i < ARRAY_SIZE(led_info); i++) {gpio_request(led_info[i].gpio,led_info[i].name);gpio_direction_output(led_info[i].gpio, 1);}//2.申请设备号alloc_chrdev_region(&dev, 0, 1, "tarena");//3.初始化字符设备对象,给字符设备对象添加操作接口cdev_init(&led_cdev, &led_fops);//4.最终向内核注册字符设备对象,一旦注册成功,//内核就有一个真实的字符设备对象并且提供了//硬件操作接口cdev_add(&led_cdev, dev, 1);return 0;
}static void led_exit(void)
{int i;//1.输出1,释放GPIO资源for(i = 0; i < ARRAY_SIZE(led_info); i++) {gpio_set_value(led_info[i].gpio, 1);gpio_free(led_info[i].gpio);}//2.释放设备号unregister_chrdev_region(dev, 1);//3.卸载字符设备对象cdev_del(&led_cdev);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
kernel_dir=/home/ww/ARM/kernel
obj-m += led_drv.o
all:make -C ${kernel_dir} SUBDIRS=$(PWD) modules
clean:make -C ${kernel_dir} SUBDIRS=$(PWD) clean
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{int fd;//应用open->软中断->内核sys_open->驱动led_openfd = open("/dev/myled", O_RDWR);if (fd < 0) {printf("打开设备失败~!n");return -1;}sleep(3);//应用close->软中断->内核sys_close->驱动led_closeclose(fd);return 0;
}
mknode /dev/myled c 244 0
本文发布于:2024-02-05 08:00:04,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170727860064754.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |