一、 驱动代码(char_driver.c)

/*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
#include <linux/init.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
#include <linux/module.h>
/*定义module_param module_param_array的头文件*/
#include <linux/moduleparam.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*三个字符设备函数*/
#include <linux/fs.h>
/*MKDEV转换设备号数据类型的宏定义*/
#include <linux/kdev_t.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
/*分配内存空间函数头文件*/
#include <linux/slab.h>/*包含函数device_create 结构体class等头文件*/
#include <linux/device.h>#define DEVICE_NAME "chardevnode"
#define DEVICE_MINOR_NUM 2
#define DEV_MAJOR 0
#define DEV_MINOR 0
#define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL");
/*声明是开源的,没有内核版本限制*/
MODULE_AUTHOR("iTOPEET_dz");
/*声明作者*/int numdev_major = DEV_MAJOR;
int numdev_minor = DEV_MINOR;/*输入主设备号*/
module_param(numdev_major,int,S_IRUSR);
/*输入次设备号*/
module_param(numdev_minor,int,S_IRUSR);static struct class *myclass;struct reg_dev
{char *data;unsigned long size;struct cdev cdev;
};
struct reg_dev *my_devices;
/*打开操作*/
static int chardevnode_open(struct inode *inode, struct file *file){printk(KERN_EMERG "chardevnode_open is success!\n");return 0;
}
/*关闭操作*/
static int chardevnode_release(struct inode *inode, struct file *file){printk(KERN_EMERG "chardevnode_release is success!\n");return 0;
}
/*IO操作*/
static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg){printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);return 0;
}ssize_t chardevnode_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops){return 0;
}ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t count, loff_t *f_ops){return 0;
}loff_t chardevnode_llseek(struct file *file, loff_t offset, int ence){return 0;
}
struct file_operations my_fops = {.owner = THIS_MODULE,.open = chardevnode_open,.release = chardevnode_release,.unlocked_ioctl = chardevnode_ioctl,.read = chardevnode_read,.write = chardevnode_write,.llseek = chardevnode_llseek,
};/*设备注册到系统*/
static void reg_init_cdev(struct reg_dev *dev,int index){int err;int devno = MKDEV(numdev_major,numdev_minor+index);/*数据初始化*/cdev_init(&dev->cdev,&my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;/*注册到系统*/err = cdev_add(&dev->cdev,devno,1);if(err){printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,err);}else{printk(KERN_EMERG "cdev_add %d is success!\n",numdev_minor+index);}
}static int scdev_init(void)
{int ret = 0,i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);if(numdev_major){num_dev = MKDEV(numdev_major,numdev_minor);ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);}else{/*动态注册设备号*/ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);/*获得主设备号*/numdev_major = MAJOR(num_dev);printk(KERN_EMERG "adev_region req %d !\n",numdev_major);}if(ret<0){printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major);        }myclass = class_create(THIS_MODULE,DEVICE_NAME);my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL);if(!my_devices){ret = -ENOMEM;goto fail;}memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));/*设备初始化*/for(i=0;i<DEVICE_MINOR_NUM;i++){my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);memset(my_devices[i].data,0,REGDEV_SIZE);/*设备注册到系统*/reg_init_cdev(&my_devices[i],i);/*创建设备节点*/device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL,DEVICE_NAME"%d",i);}printk(KERN_EMERG "scdev_init!\n");/*打印信息,KERN_EMERG表示紧急信息*/return 0;fail:/*注销设备号*/unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);printk(KERN_EMERG "kmalloc is fail!\n");return ret;
}static void scdev_exit(void)
{int i;printk(KERN_EMERG "scdev_exit!\n");/*除去字符设备*/for(i=0;i<DEVICE_MINOR_NUM;i++){cdev_del(&(my_devices[i].cdev));/*摧毁设备节点函数d*/device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));}/*释放设备class*/class_destroy(myclass);/*释放内存*/kfree(my_devices);unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
}module_init(scdev_init);
/*初始化函数*/
module_exit(scdev_exit);
/*卸载函数*/

二、Makefile

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件mini_linux_module.o
obj-m += char_driver.o #源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0#当前目录变量
PWD ?= $(shell pwd)#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:make -C $(KDIR) M=$(PWD) modules#make clean执行的操作是删除后缀为o的文件
clean:rm -rf *.mod.c *.o *.order *.ko *.mod.o *.symvers

三、应用程序(invoke_char_driver.c)

“arm-none-linux-gnueabi-gcc -o invoke_char_driver invoke_char_driver.c -static”编译应用

#include <stdio.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>main(){int fd;char *hello_node0 = "/dev/chardevnode0";char *hello_node1 = "/dev/chardevnode1";
/*O_RDWR只读打开,O_NDELAY非阻塞方式*/    if((fd = open(hello_node0,O_RDWR|O_NDELAY))<0){printf("APP open %s failed!\n",hello_node0);}else{printf("APP open %s success!\n",hello_node0);}close(fd);if((fd = open(hello_node1,O_RDWR|O_NDELAY))<0){printf("APP open %s failed!\n",hello_node1);}else{printf("APP open %s success!\n",hello_node1);}close(fd);}

四、运行

十六、字符驱动及应用相关推荐

  1. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  2. [算法系列之二十六]字符串匹配之KMP算法

    一 简介 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法).KMP算法的关键是利 ...

  3. IT餐馆—第十六回 驱动

    声明:在写这个系列文章的过程中,园子里有些人投来了怀疑.鄙视.甚至匿名谩骂,当然也有朋友跳出来支持并提出意见或建议的.我这些天想了一下,感觉写文章不一定要让所有人都接受,必定众口难调,有时为了照顾大多 ...

  4. 嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)

    ###你好!这里是风筝的博客, ###欢迎和我一起交流. 前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案. Linux早期时候,一个驱 ...

  5. ABP学习实践(十六)--领域驱动设计(DDD)回顾

    ABP框架并没有实现领域驱动设计(DDD)的所有思想,但是并不妨碍用领域驱动的思想去理解ABP库框架. 1.领域驱动设计(DDD)与微服务(MicroService)的关系? 领域驱动设计(DDD)是 ...

  6. 第四十六讲 设备驱动kobject

    第四十六讲 设备驱动 文章目录 第四十六讲 设备驱动 一.sysfs 1.发展 2.sysfs简介 3.kobject 4.kobj_type 二.设备驱动实验 1.代码 2.Makefile 3.实 ...

  7. C语言编程>第十六周 ⑦ s是全部由小写字母字符和空格字符组成的字符串,由len传入字符串的长度,请补充fun函数,该函数的功能是:统计字符串s中的单词数,结果由变量len传回。

    例题:s是全部由小写字母字符和空格字符组成的字符串,由len传入字符串的长度,请补充fun函数,该函数的功能是:统计字符串s中的单词数,结果由变量len传回.每个单词之间都由空格隔开,并且字符串s开始 ...

  8. 手把手教你搭建SpringCloud项目(十六)集成Stream消息驱动

    Spring Cloud全集文章目录: 零.什么是微服务?一看就会系列! 一.手把手教你搭建SpringCloud项目(一)图文详解,傻瓜式操作 二.手把手教你搭建SpringCloud项目(二)生产 ...

  9. S3C2416裸机开发系列十六_sd卡驱动实现

    S3C2416裸机开发系列十六 sd卡驱动实现 象棋小子    1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.数据传输快.可插拔.安全性好等优 ...

  10. 【正点原子MP157连载】 第十六章 UART串口通信实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

最新文章

  1. CxImage类库的简介
  2. stat用法:获取文件对应权限的数字
  3. 【FPGA】ROM/EPROM的设计(使用case的方式初始化)
  4. Altium Designer圆形、椭圆形铺铜
  5. STM32f103 can的两个接收fifo使用方法
  6. 基于 KubeVela 与 Kubernetes 打造“无限能力”的开放 PaaS
  7. java的svn插件maver_eclipse中 svn插件导入maven项目
  8. Linux下find命令使用
  9. LeetCode 703. 数据流中的第K大元素(优先队列)
  10. 在命令提示符中运行c语言程序,【命令提示符运行exe】命令提示符运行文件_命令提示符运行程序-系统城...
  11. vscode php插件_「PHP从入门到颈椎病康复」基础篇——HelloWorld
  12. 涉密计算机清退登记表,涉密载体登记表.doc
  13. Java、JSP网吧自动计费收费管理系统
  14. php使用cookie获取浏览记录,php使用cookie存库浏览记录详解
  15. java代码实现端口是否ping通
  16. FreeRTOS学习笔记:FreeRTOS如何入门?任务就绪态、阻塞态、挂起态,傻傻分不清?
  17. easyboot-code-generate 自动生成代码
  18. token与JWT详细介绍
  19. 软件设计师----计算机网络
  20. java学生成绩分90及格_Java基础练习:题目:利用条件运算符的嵌套来完成此题:学习成绩=90分的同学用A表示,60-89分之间的用B表示,60分以下 的用C表示。 - 菜鸟头头...

热门文章

  1. 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to
  2. UA MATH567 高维统计III 随机矩阵8 社区发现 Spectral Clustering的理论分析
  3. C++对象内存模型学习
  4. asp.net ashx 学习总结
  5. 图解Windows下使用SSH Secure Shell Client远程连接Linux
  6. 牛客网——10进制 VS 2进制
  7. dp_c_区间dp_g
  8. 对Dev的GridControl/GridView控件进行分组并展开操作
  9. 最新以及历史各版本 .NET Framework 的下载
  10. Dapper+SqlServerCe部署