linux内核设备节点增加,/dev下添加设备节点的方法步骤

将自己开发的内核代码加入到Linux内核中,需要3个步骤:

1、确定把自己开发代码放入到内核合适的位置

将demo_chardev.c文件拷贝到.../drivers/char/目录下。

demo_chardev.c

#include

#include

#include

/*结构体file_operations定义的头文件*/

#include

/*声明copy_to/from_user函数的头文件*/

#include

/*声明class_create 和device_create相关信息*/

#include

#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

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_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

#include

#include

#include

#include

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(": 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(": 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(跟当前内核版本同名)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值