您的位置:首页 > 运维架构 > Linux

Linux 驱动开发-字符设备驱动

2010-08-19 10:16 567 查看
***************************************************************

1。首先书写字符驱动程序。

/*globalvar.c*/

#include <linux/module.h> //模块所需的大量符号和函数定义

#include <linux/init.h> //指定初始化和清楚函数

#include <linux/fs.h> //文件系统相关的函数和头文件

#include <linux/cdev.h> //cdev结构的头文件

#include <asm/uaccess.h> //在内核和用户空间中移动数据的函数

MODULE_LICENSE("GPL"); //指定代码使用的许可证

//文件操作函数的声明

int globalvar_open(struct inode *, struct file *);

int globalvar_release(struct inode *, struct file *);

ssize_t globalvar_read(struct file *, char *, size_t, loff_t *);

ssize_t globalvar_write(struct file *, const char *, size_t, loff_t *);

int dev_major = 200; //指定主设备号

int dev_minor = 0; //指定次设备号

struct file_operations globalvar_fops= //将文件操作与分配的设备号相连

{

owner: THIS_MODULE, //指向拥有该模块结构的指针

open: globalvar_open,

release: globalvar_release,

read: globalvar_read,

write: globalvar_write,

};

struct globalvar_dev //用来表示我们定义设备的结构

{

int global_var; //这个变量代表要操作的设备

struct cdev cdev; //内核中表示字符设备的结构

};

struct globalvar_dev *my_dev; //设备结构的指针

static void __exit globalvar_exit(void) //退出模块时的操作

{

dev_t devno=MKDEV(dev_major, dev_minor); //dev_t是用来表示设备编号的结构

cdev_del(&my_dev->cdev); //从系统中移除一个字符设备

kfree(my_dev); //释放自定义的设备结构

unregister_chrdev_region(devno, 1); //注销已注册的驱动程序

printk("globalvar unregister success/n");

}

static int __init globalvar_init(void) //初始化模块的操作

{

int ret, err;

dev_t devno=MKDEV(dev_major, dev_minor);

//动态分配设备号,次设备号已经指定

ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar");

//保存动态分配的主设备号

dev_major=MAJOR(devno);

//根据期望值分配设备号

//ret=register_chrdev_region(devno, 1, "globalvar");

if(ret<0)

{

printk("globalvar register failure/n");

globalvar_exit(); //如果注册设备号失败就退出系统

return ret;

}

else

{

printk("globalvar register success/n");

}

//为设备在内核空间分配空间

my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL);

if(!my_dev)

{

ret=-ENOMEM; //如果分配失败返回错误信息

printk("create device failed/n");

}

else //如果分配成功就可以完成设备的初始化

{

my_dev->global_var=0; //设备变量初始化为0

cdev_init(&my_dev->cdev, &globalvar_fops); //初始化设备中的cdev结构

my_dev->cdev.owner=THIS_MODULE; //初始化cdev中的所有者字段

err=cdev_add(&my_dev->cdev, devno, 1); //向内核添加这个cdev结构的信息

if(err<0)

printk("add device failure/n"); //如果添加失败打印错误消息

}

return ret;

}

//打开设备文件系统调用对应的操作

int globalvar_open(struct inode *inode, struct file *filp)

{

struct globalvar_dev *dev;

//根据inode结构的cdev字段,获得整个设备结构的指针

dev=container_of(inode->i_cdev, struct globalvar_dev, cdev);

//将file结构中的private_data字段指向已分配的设备结构

filp->private_data=dev;

return 0;

}

//关闭设备文件系统调用对应的操作

int globalvar_release(struct inode *inode, struct file *filp)

{

return 0;

}

//读设备文件系统调用对应的操作

ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)

{

//获取指向已分配数据的指针

struct globalvar_dev *dev=filp->private_data;

dev->global_var=dev->global_var+1;

//将设备变量值复制到用户空间

if(copy_to_user(buf, &dev->global_var, sizeof(int)))

{

return -EFAULT;

}

return sizeof(int); //返回读取数据的大小

}

//写设备文件系统调用对应的操作

ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)

{

//获取指向已分配数据的指针

struct globalvar_dev *dev=filp->private_data;

//从用户空间复制数据到内核中的设备变量

if(copy_from_user(&dev->global_var, buf, sizeof(int)))

{

return -EFAULT;

}

return sizeof(int); //返回写数据的大小

}

module_init(globalvar_init); //模块被装载时调用globalvar_init

module_exit(globalvar_exit); //模块被卸载时调用globalvar_exit

***************************************************************

2。书写Makefile文件

#Makefile

ifneq ($(KERNELRELEASE), )

obj-m := globalvar.o

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

all:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:

$(RM) -f *~ *.o modules.* *.mod.* Module.* *.ko

endif

***************************************************************

3。在终端输入命令> make。加载模块到内核>sudo insmod globalvar.ko.

***************************************************************

4。输入dmesg命令查看模块是否加载内核中

[ 5891.581723] globalvar register success

***************************************************************

5。终端键入命令>cat /proc/devices ,查看设备号 250 globalvar

6。sudo mknod /dev/globalvar c 250 0

***************************************************************

7。测试程序

/*test.c*/

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <fcntl.h>

int main()

{

int fd, num;

fd=open("/dev/globalvar", O_RDWR, S_IRUSR|S_IWUSR); //可读写方式打开设备文件

if(fd!=-1)

{

read(fd, &num, sizeof(int)); //读取设备变量

printf("The globalvar is %d/n", num);

printf("Please input the num written to globalvar/n");

scanf("%d", &num);

write(fd, &num, sizeof(int)); //写设备变量

read(fd, &num, sizeof(int)); //再次读取刚才写的值

printf("The globalvar is %d/n", num);

close(fd); //关闭设备文件

}

else

{

printf("Device open failure/n");

return -1;

}

return 0;

}

编译测试程序

gcc -o test test.c

$ ./test

Device open failure

$ ls -l /dev/globalvar

crw-r--r-- 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar

$ sudo chmod 777 /dev/globalvar

$ ls -l /dev/globalvar

crwxrwxrwx 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar

$ sudo chmod 767 /dev/globalvar

$ ls -l /dev/globalvar

crwxrw-rwx 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar

$ sudo chmod 700 /dev/globalvar

$ ls -l /dev/globalvar

crwx------ 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar

$ sudo chmod 777 /dev/globalvar

$ ./test

The globalvar is 1

Please input the num written to globalvar

4

The globalvar is 5

$

**************************************************************

感谢伟哥的帮忙和热心的解答。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: