多节点+内核文件接口
目录
一、多节点
1、什么是多节点、多节点的意义
2、多节点的实现方法
3、多节点下的流水灯
二、内核文件接口
1、open 和 close 文件接口
2、read 和 write 文件接口
3、按键的驱动控制LED灯 示例
一、多节点
1、什么是多节点、多节点的意义
多节点:一个设备对应一个节点文件(设备文件)
意义:增加硬件的独立性
2、多节点的实现方法
在一个驱动文件下实现多节点
只要是靠Linux2.6下的 cdev_add
cdev 支持连续注册多个设备文件!
3、多节点下的流水灯
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/device.h"
dev_t devnum;
struct cdev cdev;
struct file_operations ops;
struct class * cls;//四个设备文件共用了一个打开接口和关闭接口
/*现在你再上层调用 open 不管你打开的是 LED1 还是LED2 亦或是LED3那么他都会调用 myled_open请问我如何区分谁再打开造成底层的调用
*/
int myled_open(struct inode * inode, struct file * file)
{/* inode 传参里面有个成员变量i_rdev -- 记录的是调用底层open打开设备的设备号!*/if(inode->i_rdev == devnum)//LED1 {gpio_set_value(EXYNOS4X12_GPM4(0),0);}else if(inode->i_rdev == devnum+1 ) //LED2 {gpio_set_value(EXYNOS4X12_GPM4(1),0);}else if(inode->i_rdev == devnum+2 ) //LED3 {gpio_set_value(EXYNOS4X12_GPM4(2),0);}else if(inode->i_rdev == devnum+3 ) //LED4{ gpio_set_value(EXYNOS4X12_GPM4(3),0);}return 0;
}
int myled_close(struct inode * inode, struct file * file)
{if(inode->i_rdev == devnum)//LED1 {gpio_set_value(EXYNOS4X12_GPM4(0),1);}else if(inode->i_rdev == devnum+1 ) //LED2 {gpio_set_value(EXYNOS4X12_GPM4(1),1);}else if(inode->i_rdev == devnum+2 ) //LED3 {gpio_set_value(EXYNOS4X12_GPM4(2),1);}else if(inode->i_rdev == devnum+3 ) //LED4{ gpio_set_value(EXYNOS4X12_GPM4(3),1);}return 0;
}static int __init led_init(void)
{//1:申请四个设备号int ret = alloc_chrdev_region(&devnum,0,4,"led");if(ret < 0){printk("申请设备号失败\r\n");return -EINVAL;}//2 :Linux2.6 核心结构体初始化 ops.owner = THIS_MODULE;ops.open = myled_open;ops.release = myled_close;cdev_init(&cdev, &ops);cdev_add(&cdev,devnum,4);/*由于注册设备公用一个cdev核心结构体也就是公用一个ops也就是他们四个设备公用一套文件接口!!!*///3: 生成设备文件cls = class_create(THIS_MODULE, "led");device_create(cls ,NULL, devnum,NULL,"LED1");device_create(cls ,NULL, devnum+1,NULL,"LED2");device_create(cls ,NULL, devnum+2,NULL,"LED3");device_create(cls ,NULL, devnum+3,NULL,"LED4");/*你现在的四个设备文件公用一套文件接口!!!你还是不好做流水灯*/return 0;
}static void __exit led_exit(void)
{//销毁设备文件device_destroy(cla,devnum);device_destroy(cla,devnum+1);device_destroy(cla,devnum+2);device_destroy(cla,devnum+3);//释放类结构体空间class_destroy(cla);//删除Linux2.6设备cdev_del(&cdev);//释放设备号unregister_chrdev_region(devnum,4);}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
二、内核文件接口
1、open 和 close 文件接口
int (*open) (
struct inode * inode,
struct file * file
);
struct inode
{
i_rdev;//设备的设备号!
i_private;
//设备节点私有数据
//该指针可以指向任何地方
//一般用的比较少
//可以当作传参使用
}
struct file * file{
void *private_data;
//此空指针的用法与 i_private差不多
//也是提供给用户的指针
//可以指向任何地方
//一般多节点中当做传参使用
}
2、read 和 write 文件接口
ssize_t (*read) (struct file * file, char __user * buf, size_t size , loff_t * offt);
ssize_t (*write) (struct file * file, const char __user * buf, size_t, loff_t * offt);
file:
他就是 open和close的file指针
主要用 private_data进行传参
给 read 和 write
大部分情况下用于多节点下
区分不同设备的情况!
read的buf:
你的上层的read的目的一定是
读内核的数据!
那么你内核层的read一定在
给用户层写入数据!
而此buf就是上层read传过来的所谓的
空间
* 但是这个read 不能让你直接访问!
内核专用的将数据拷贝到用户层!
#include <linux/uaccess.h>
copy_to_user(
void __user *to,
const void *from,
unsigned long n
);
to-> buf
from:从哪拷贝数据!
n:你要拷贝过去的长度
顺便也解释了
int read(
int fd,
void * buf
int size
);
read(fd,buf,999);
读到的长度谁决定的
内核!
write的buf:
用户层write一定是在给内核层写数据
所以 内核层实际在读取用户层数据
buf
首先它就是用户层传过来的数据!
还是跟read 的buf一样 不能直接操作
只能通过内核函数操作
copy_from_user(
void *to,
const void __user *from,
unsigned long n
);
to:你现在拷贝数据放到哪!
from:拷贝的数据来自哪--buf
n:你要拷贝几个字节呀!
size 内核read/write第三个参数
size:
实际上内核传数据的长度!
offt:
偏移量仅仅适用于块设备文件!
对于字符设备文件而言没有偏移量概念
3、按键的驱动控制LED灯 示例
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/gpio.h>//#include <asm/uaccess.h>#include <linux/uaccess.h>/*按键GPX3_2 -- KEY1GPX3_3 -- KEY2GPX3_4 -- KEY3GPX3_5 -- KEY4按键按下低松开高*/dev_t devnum;struct cdev cdev;struct file_operations ops;struct class * cls;int mykey_open(struct inode * inode, struct file * file){//如果按键没有初始化一般在此处初始化!file->private_data = &inode->i_rdev;if(inode->i_rdev == devnum){//gpio_direction_input(EXYNOS4_GPX3(2));}else if(inode->i_rdev == devnum+1){//gpio_direction_input(EXYNOS4_GPX3(3));}else if(inode->i_rdev == devnum+2){//gpio_direction_input(EXYNOS4_GPX3(4));}else if(inode->i_rdev == devnum+3){//gpio_direction_input(EXYNOS4_GPX3(5));}return 0;}int mykey_close(struct inode * inode, struct file * file){file->private_data = NULL;return 0;
}ssize_t mykey_read(struct file * file, char __user * buf, size_t size , loff_t * offt){uint8_t keyvaule = 0;dev_t * devnump = file->private_data;if(* devnump == devnum){keyvaule = gpio_get_value(EXYNOS4_GPX3(2));}else if(* devnump == devnum+1){keyvaule = gpio_get_value(EXYNOS4_GPX3(3));}else if(* devnump == devnum+2){keyvaule = gpio_get_value(EXYNOS4_GPX3(4));}else if(* devnump == devnum+3){keyvaule = gpio_get_value(EXYNOS4_GPX3(5));}copy_to_user(buf,&keyvaule,1);return 0;}static int __init key_init(void){//1:申请设备号alloc_chrdev_region(&devnum,0,4, "keydevnum");//2:初始化Linux2.6 核心结构体ops.open = mykey_open;ops.read = mykey_read;ops.release= mykey_close;cdev_init(&cdev,&ops);cdev_add(&cdev,devnum,4);//3:生成设备文件cls = class_create(THIS_MODULE,"keyclass");device_create(cls,NULL,devnum, NULL,"key1");device_create(cls,NULL,devnum+1, NULL,"key2");device_create(cls,NULL,devnum+2, NULL,"key3");device_create(cls,NULL,devnum+3, NULL,"key4");return 0;}static void __exit key_exit(void){ }module_init(key_init);module_exit(key_exit);MODULE_LICENSE("GPL");
多节点+内核文件接口相关推荐
- 基础IO(文件接口、安装内核源码超详细步骤图解、静态库与动态库)
基础IO C语言的文件操作接口 fopen fclose fread fwrite fseek 系统调用文件接口 open close read write lseek 安装内核源码 文件描述符&am ...
- linux 内核文件结构,linux-011内核文件结构图
linux-011内核文件结构图 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 Linux内核文件结构图LinuxI -boot系统引 ...
- Linux内核编程接口函数
Linux内核编程接口函数 转载请注明出处: http://blog.csdn.net/drivelinux/article/details/8656280 字符设备相关函数 1.alloc_chrd ...
- Linux内核文件操作
Linux内核文件操作 前言 一.文件操作结构体 二.VFS之file_operations对象 1.文件打开filp_open 2.文件关闭filp_close 3.文件读取vfs_read 4.文 ...
- linux设备usb节点和硬件接口,所谓设备驱动即驱使硬件设备行动,带你深入理解linux的设备驱动......
原标题:所谓设备驱动即驱使硬件设备行动,带你深入理解linux的设备驱动... 设备驱动最通俗的解释就是"驱使硬件设备行动".操作系统是通过各种驱动程序来驾驭硬件设备的,它为用户屏 ...
- linux启动参数关闭cgroup,Linux的cgroup功能(三):cgroup controller汇总和控制器的参数(文件接口)...
cgroup controller列表 cgroup v1 支持的controller cgroup v2 支持的controller 说明 这里将罗列cgroup支持的controllers,每个c ...
- oracle实现数据目录共享,为共享文件系统创建特定于节点的文件和目录
为共享文件系统创建特定于节点的文件和目录 在共享文件系统上安装 Oracle 软件后,所有群集节点都可以访问由 ORACLE_HOME 环境变量指定的目录中的所有文件.但是,某些 Oracle 文件和 ...
- Linux内核文件vmlinux 和压缩后的bzImage文件格式分析
Linux内核文件vmlinux 和压缩后的bzImage文件格式分析 ================= 1. 需要使用的命令 ================ readelf -- 显示el ...
- 简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程。
简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程. 参考答案: Linux通过i节点表将文件的逻辑结构和物理结构进行转换. i 节点是一个64字节长的表,表中包含了文件的相关信 ...
最新文章
- 40.简述操作系统中调用过程?
- asp.net mvc源码分析-Action篇 Action的执行
- C++多态(一)——多态的定义、虚函数、静态绑定和动态绑定
- 百度二年级手工机器人_使用盈首AI炒股机器人,能获得超高超额收益率
- 开源中国社区(OsChina.NET) 8月第3周 精彩回顾
- mate40升级鸿蒙系统教程,mate40鸿蒙系统怎么升级 教程如下
- 修改数据库长度mysql_mysql 修改数据库长度
- Qt交叉编译移植arm开发板
- java jimi_绝对经典Java开源工具Jimi处理图片大小及格式转换及打水印(源码)
- jvm 性能调优之 jmap
- Charles安装及使用教程
- 【api】添加了权限管理的一部分
- 负记账与剩余项目清账虚增借贷的问题
- One-Hot Encoding
- 【Android源码面试宝典】MMKV从使用到原理分析(二)
- Vue-idea的搭建
- Hive 高级篇(调优)
- php的数组、排序、查找
- lighttpd+flash+PHP大文件上传,带上传进度显示
- Windows官方原版操作系统下载