目录

一、多节点

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");

多节点+内核文件接口相关推荐

  1. 基础IO(文件接口、安装内核源码超详细步骤图解、静态库与动态库)

    基础IO C语言的文件操作接口 fopen fclose fread fwrite fseek 系统调用文件接口 open close read write lseek 安装内核源码 文件描述符&am ...

  2. linux 内核文件结构,linux-011内核文件结构图

    linux-011内核文件结构图 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 Linux内核文件结构图LinuxI -boot系统引 ...

  3. Linux内核编程接口函数

    Linux内核编程接口函数 转载请注明出处: http://blog.csdn.net/drivelinux/article/details/8656280 字符设备相关函数 1.alloc_chrd ...

  4. Linux内核文件操作

    Linux内核文件操作 前言 一.文件操作结构体 二.VFS之file_operations对象 1.文件打开filp_open 2.文件关闭filp_close 3.文件读取vfs_read 4.文 ...

  5. linux设备usb节点和硬件接口,所谓设备驱动即驱使硬件设备行动,带你深入理解linux的设备驱动......

    原标题:所谓设备驱动即驱使硬件设备行动,带你深入理解linux的设备驱动... 设备驱动最通俗的解释就是"驱使硬件设备行动".操作系统是通过各种驱动程序来驾驭硬件设备的,它为用户屏 ...

  6. linux启动参数关闭cgroup,Linux的cgroup功能(三):cgroup controller汇总和控制器的参数(文件接口)...

    cgroup controller列表 cgroup v1 支持的controller cgroup v2 支持的controller 说明 这里将罗列cgroup支持的controllers,每个c ...

  7. oracle实现数据目录共享,为共享文件系统创建特定于节点的文件和目录

    为共享文件系统创建特定于节点的文件和目录 在共享文件系统上安装 Oracle 软件后,所有群集节点都可以访问由 ORACLE_HOME 环境变量指定的目录中的所有文件.但是,某些 Oracle 文件和 ...

  8. Linux内核文件vmlinux 和压缩后的bzImage文件格式分析

    Linux内核文件vmlinux 和压缩后的bzImage文件格式分析 ================= 1. 需要使用的命令 ================ readelf    -- 显示el ...

  9. 简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程。

    简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程. 参考答案: Linux通过i节点表将文件的逻辑结构和物理结构进行转换. i 节点是一个64字节长的表,表中包含了文件的相关信 ...

最新文章

  1. 40.简述操作系统中调用过程?
  2. asp.net mvc源码分析-Action篇 Action的执行
  3. C++多态(一)——多态的定义、虚函数、静态绑定和动态绑定
  4. 百度二年级手工机器人_使用盈首AI炒股机器人,能获得超高超额收益率
  5. 开源中国社区(OsChina.NET) 8月第3周 精彩回顾
  6. mate40升级鸿蒙系统教程,mate40鸿蒙系统怎么升级 教程如下
  7. 修改数据库长度mysql_mysql 修改数据库长度
  8. Qt交叉编译移植arm开发板
  9. java jimi_绝对经典Java开源工具Jimi处理图片大小及格式转换及打水印(源码)
  10. jvm 性能调优之 jmap
  11. Charles安装及使用教程
  12. 【api】添加了权限管理的一部分
  13. 负记账与剩余项目清账虚增借贷的问题
  14. One-Hot Encoding
  15. 【Android源码面试宝典】MMKV从使用到原理分析(二)
  16. Vue-idea的搭建
  17. Hive 高级篇(调优)
  18. php的数组、排序、查找
  19. lighttpd+flash+PHP大文件上传,带上传进度显示
  20. Windows官方原版操作系统下载

热门文章

  1. 语义分割常用指标详解(附代码)
  2. 一加Ace竞速版,手游党的开心搭档
  3. IAR使用ST-Link下载仿真
  4. 使用photoshop对图片像素级的标注
  5. uniPaas入门(magic最新版本改名叫uniPaas,unipaas也就是以前的magic)
  6. 2021年茶艺师(中级)复审考试及茶艺师(中级)理论考试
  7. 用js做一个鼠标惯性动画
  8. 抖音引流必须知道的三个要点!!!!
  9. 配置mysql数据库端口号_数据库配置时要注意端口号
  10. 如何将图片格式转换为ico格式