/dev下添加设备节点的方法步骤(通过device_create)
将自己开发的内核代码加入到Linux内核中,需要3个步骤:
1、确定把自己开发代码放入到内核合适的位置
将demo_chardev.c文件拷贝到.../drivers/char/目录下。
demo_chardev.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- /*结构体file_operations定义的头文件*/
- #include <linux/fs.h>
- /*声明copy_to/from_user函数的头文件*/
- #include <linux/uaccess.h>
- /*声明class_create 和device_create相关信息*/
- #include <linux/device.h>
- #define DEMO_DEBUG
- #ifdef DEMO_DEBUG
- #define dem_dbg(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
- #else
- #define dem_dbg(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
- #endif
- #define DEVICE_COUNT 2
- /*记录当前驱动所占用的主设备号*/
- static int major = 0;
- static int demo_open (struct inode *pnode, struct file *filp)
- {
- dem_dbg("[kern func]: %s major: %d minor: %d\n",
- __FUNCTION__, imajor(pnode), iminor(pnode));
- return 0;
- }
- static ssize_t demo_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)
- {
- unsigned char ary[100] = "you are reading successfully!";
- unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值
- int retval;
- dem_dbg("[kern func]: %s major: %d minor: %d\n",
- __FUNCTION__, imajor(filp->f_dentry->d_inode),
- iminor(filp->f_dentry->d_inode));
- //file结构体的f_flags成员可用来判断是否阻塞读取,然后进行相应处理
- if(copy_to_user(buf, ary, len) != 0){
- retval = -EFAULT;
- goto cp_err;
- }
- return len; //成功返回实际传输的字节数
- cp_err:
- return retval;
- }
- static ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
- {
- unsigned char ary[100] = "";
- unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值
- int retval;
- dem_dbg("[kern func]: %s major: %d minor: %d\n",
- __FUNCTION__, imajor(filp->f_dentry->d_inode),
- iminor(filp->f_dentry->d_inode));
- if(copy_from_user(ary, buf, len) != 0){
- retval = -EFAULT;
- goto cp_err;
- }
- printk("[msg]: writing context: %s\n",ary);
- return len; //成功返回实际传输的字节数
- cp_err:
- return retval;
- }
- static int demo_release (struct inode *pnode, struct file *filp)
- {
- dem_dbg("[kern func]: %s major: %d minor: %d\n",
- __FUNCTION__, imajor(pnode), iminor(pnode));
- return 0;
- }
- /*@定义file_operations结构体变量*/
- static struct file_operations fops = {
- .owner = THIS_MODULE,
- .read = demo_read,
- .write = demo_write,
- .open = demo_open,
- .release = demo_release,
- };
- static struct class *demo_class;
- static int __init drvdemo_init(void)
- {
- struct device *demo_device;
- int i;
- int retval;
- dem_dbg("[msg]:this is a driver demo, in module initial function\n");
- /*注册字符驱动函数,成功 返回动态分配好的主设备号,失败
- *返回错误码(负值)*/
- major = register_chrdev(0, "demo_chrdev", &fops);
- if(major < 0){
- retval = major;
- goto chrdev_err;
- }
- /*创建设备类*/
- demo_class = class_create(THIS_MODULE,"demo_class");
- if(IS_ERR(demo_class)){
- retval = PTR_ERR(demo_class);
- goto class_err;
- }
- /*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/
- for(i=0; i<DEVICE_COUNT; i++){ //最多可创建255个设备节点(register_chrdev函数会申请0-254范围的从设备号)
- demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);
- if(IS_ERR(demo_device)){
- retval = PTR_ERR(demo_device);
- goto device_err;
- }
- }
- return 0;
- device_err:
- while(i--) //设备节点创建的回滚操作 device_destroy(demo_class,MKDEV(major, i));
- class_destroy(demo_class); //删除设备类
- class_err:
- unregister_chrdev(major, "demo_chrdev");
- chrdev_err:
- return retval;
- }
- static void __exit drvdemo_exit(void)
- {
- int i;
- dem_dbg("[msg]:in module exit function\n");
- /*注销字符驱动函数,无返回值,major为已分配的主设备号*/
- unregister_chrdev(major, "demo_chrdev");
- /*删除设备节点和设备类*/
- for(i=0; i<DEVICE_COUNT; i++)
- device_destroy(demo_class,MKDEV(major, i));
- class_destroy(demo_class);
- }
- module_init(drvdemo_init);
- module_exit(drvdemo_exit);
- MODULE_LICENSE("Dual BSD/GPL"); //BSD/GPL双重许可证
- MODULE_AUTHOR("hanbo"); //模块作者(可选)
- MODULE_DESCRIPTION("used for studing linux drivers"); //模块儿简介(可选)
2、把自己开发的功能增加到Linux内核的配置选项中,使用户能够选择此功能
vi drivers/char/Konfig 在文件结尾,endmenu的前面加入一个config选项
- config DEMO_CHARDEV
- bool "demo_chardev driver for hanbo chardev boards"
- default y
- help
- this is CHARDEV driver for hanbo chardev boards.
3、构建或修改Makefile,根据用户的选择,将相应的代码编译到最终生成的Linux内核中去
make menuconfig(添加配置选项)(如果提示找不到“ncurses”库则执行命令: sudo apt-get install libncurses5-dev )
Device driver -->
character devices ->
[*] demo_chardev driver for hanbo chardev boards
4、vi drivers/char/Makefile 添加内容如下:
..........
obj-$(CONFIG_DEMO_CHARDEV) +=demo_chardev.o (添加)
obj-$(CONFIG_JS_RTC) +=js-rtc.o(自带)
js-rtc-y = rtc.o (自带)
5、make (更新内核镜像到开发板)
6、交叉编译测试程序,放到开发板运行
arm-linux-gcc-gcc test.c -o demo
test.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
- int main(int argc, char *argv[])
- {
- int fd1 = 0, fd2 = 0;
- unsigned char buf1[100] = "I am a test program!";
- unsigned char buf2[100] = {0};
- int retval;
- //以读写、不阻塞方式打开设备文件
- fd1 = open("/dev/demo0", O_RDWR | O_NONBLOCK);
- if(fd1 < 0){
- perror("open /dev/demo1");
- goto out;
- }
- //以只读、阻塞方式打开设备文件
- fd2 = open("/dev/demo1", O_RDONLY);
- if(fd2 < 0){
- perror("open /dev/demo2");
- goto out;
- }
- //成功返回实际写入字节数,失败返回负值
- retval = write(fd1, buf1, strlen(buf1)+1);
- if(retval < 0){
- perror("writing fd1 failed!");
- goto out;
- }
- printf("<user space>: write bytes: %d write content: %s\n", retval, buf1);
- //成功返回实际读取字节数,失败返回负值
- retval = read(fd2, buf2, sizeof(buf2));
- if(retval < 0){
- perror("reading fd2 failed!");
- goto out;
- }
- printf("<user space>: read bytes: %d read content: %s\n", retval, buf2);
- return 0;
- out:
- if(fd1 > 0)
- close(fd1);
- if(fd2 > 0)
- close(fd2);
- return -1;
- }
二、手动加载驱动 .ko文件
1、上面的demo_chardev.c文件放到内核下编译生成 .ko文件
Makefile
- #如果已定义KERNELRELEASE,说明是由内核构造系统调用的
- #可以利用内建语句
- ifneq ($(KERNELRELEASE),)
- obj-m +=demo_chrdev.o
- #此时由内核构造系统调用
- else
- #定义并记录内核源码路径
- KERNELDIR = /home/hanbo/linux-2.6.35.7(自己源码路径,2.6.35.7指当前内核版本)
- #记录当前工程目录
- PWD := $(shell pwd)
- default:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- @rm -rf *.o .t* .m* .*.cmd *.mod.c *.order *.symvers
- endif
- clean:
- rm -rf *.ko *.o .t* .m* .*.cmd *.mod.c *.order *.symvers
2、 然后用命令加载 .ko 驱动
lsmod 列举当前系统中的所有模块
lsmod 列举当前系统中的所有模块
rmmod xxx 卸载指定模块(不需要.ko后缀)
3、如果自己编译的代码中没有用
/*创建设备类*/
demo_class = class_create(THIS_MODULE,"demo_class");
/*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/
demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);
则需要手动添加设备节点
mknod /dev/demo1 c 主设备号 0
mknod /dev/demo2 c 主设备号 1
注意:若卸载时出现提示 rmmod:chdir(2.6.35.7):No such file or directory
则在开发板根文件系统下创建目录:/lib/modules/2.6.35.7(跟当前内核版本同名)
/dev下添加设备节点的方法步骤(通过device_create)的更多相关文章
- Linux /dev 自动创建设备节点
#include <linux/module.h> #include <linux/module.h> #include <linux/kernel.h> #inc ...
- Android 6.0中在/dev下添加新设备驱动下Selinux相关设置【转】
本文转载自:https://blog.csdn.net/fantasy_wxe/article/details/52013922 错误1: 07-23 13:06:57.617 117 117 ...
- linux系统下添加新硬盘的方法详解
对于linux新手来说,在linux上添加新硬盘,是很有挑战性的一项工作. 在Linux服务器上把硬盘接好,启动linux,以root登陆. fdisk -l ## 这里是查看目前系统上有几块硬盘 D ...
- android源码framework下添加新资源的方法
编译带有资源的jar包,需要更改frameworks层,方法如下: 一.增加png类型的图片资源 1.将appupdate模块所有用到的png格式图片拷贝到framework/base/core/re ...
- WordPress 添加Meta Box的方法步骤
需要使用到add meta boxes Action,该Action允许我们为任何文章类型注册Meta Box,在该Action中,我们需要使用add_meta_box()方法来添加Meta Box的 ...
- LINUX下添加磁盘空间的方法详解
给Linux系统添加磁盘空间在工作会经常遇到. 在添加第二块磁盘一般系统默认为hdb(IDE硬盘)sdb(SCSI 硬盘),以hdb为例. linux-isep:~ # fdisk /dev/hdb ...
- eclipse下添加viplugin插件的方法
http://www.viplugin.com/ 在eclipse根目录下建立文件:viplugin2.lic,然后在里面添加以下字符串: nd4UFjUMBADcUSeSW8ocLKoGP3lpbW ...
- JS添加父节点的方法。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【总文档】rac增加新节点的方法步骤 How to Add Node/Instance or Remove Node/Instance in 10gR2, 11gR1, 11gR2 and 12c Oracle Clusterware and RAC
[总文档]How to Add Node/Instance or Remove Node/Instance in 10gR2, 11gR1, 11gR2 and 12c Oracle Clusterw ...
随机推荐
- 【2018.9.20】JOI 2017 Final T3「JOIOI 王国 / The Kingdom of JOIOI」
题目链接 题目描述 JOIOI 王国是一个 $H$ 行 $W$ 列的长方形网格,每个 $1\times 1$ 的子网格都是一个正方形的小区块.为了提高管理效率,我们决定把整个国家划分成两个省 $JOI ...
- 转载: LINK : fatal error LNK1104: 无法打开文件“mfc71.lib”的原因又一例
转载地址:http://blog.csdn.net/mxclxp/article/details/8196142 LINK : fatal error LNK1104: 无法打开文件“mfc71.li ...
- java多线程总结一:线程的两种创建方式及比较
1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行.当程序作为一个应 ...
- 隐藏video标签的下载按钮
问题: 使用video标签时,有些浏览器会显示视频的下载按钮,而这并不是我们需要的功能,必须想办法去掉. 解决方法: 使用下面的css可以达到隐藏下载按钮的效果,但是点击下载的位置,还是能出现开始下载 ...
- android图片上传
package com.example.center; import java.io.ByteArrayOutputStream;import java.io.InputStream; import ...
- Perl、PHP、Python、Java和Ruby的比较
提问 ◆ Perl.Python.Ruby和PHP各自有何特点? ◆ 为什么动态语言多作为轻量级的解决方案? ◆ LAMP为什么受欢迎? ◆ Ruby on Rails为什么会流行? ◆ 编程语言的发 ...
- [bzoj3308]九月的咖啡店_欧拉筛素数_费用流
bzoj-3308 九月的咖啡店 题目大意:深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这里若干种兑在一起.不过有些原料不 ...
- All you need to know about SYN floods
http://blog.dubbelboer.com/ Date: 09 Apr 2012Author: Erik Dubbelboer SYN cookies So one day I notice ...
- CentOS6.5升级手动安装GCC4.8.2 与 CentOS 6.4 编译安装 gcc 4.8.1
http://blog.163.com/zhu329599788@126/blog/static/6669335020161179259975 http://www.cnblogs.com/codem ...
- 【kotlin】报错:required:LIst<XXX> found:List<Unit>此类型的问题
出现问题如下: 解决方式如下: 解决思路:上面报出来的错误很明显,就是说想要的是List<XXX>类型但是给的却是List<Unit>类型,给的不是它想要的嘛 关键就是解决问题 ...