Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得设备操作犹如文件一般。在应用程序看来,硬件设备只 是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open ()、close ()、read ()、write () 等
该程序主要是在TQ2440开发板上完成对一段内存的读写,驱动程序中实现了简单的read、write、open、release等功能。
以下是fs.c的驱动程序代码
该程序主要是在TQ2440开发板上完成对一段内存的读写,驱动程序代码如下
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/kernel.h>
#include<linux/device.h>
#include<asm/uaccess.h>
#include<linux/errno.h>
#include"../fs/ntfs/malloc.h" //该头文件为kfree和malloc函数所在位置
#define DEVICE_NAME "FS" //定义设备名称
unsigned int fs_major=0;
static char *data;
static int test_open(struct inode *inode,struct file *file)
{
// MOD_INC_USE_COUNT;
printk("this is open\n");
return 0;
}
static int test_release(struct inode *inode,struct file *file)
{
// MOD_DEC_USE_COUNT;
printk("this is released\n");
return 0;
}
static ssize_t test_read(struct file *file,char *buf,size_t count,loff_t *f_pos)
{
int len;
if(count<0)
{
return -EINVAL;
}
len=strlen(data);
if(len<count)
{
count=len;
}
copy_to_user(buf,data,count+1);
return count;
}
//loff_t *f_pos 为当前的文件指针位置,即文件的读写位置
static ssize_t test_write(struct file *file,const char *buffer,size_t count,loff_t *f_pos)
{
if(count<0)
{
return -EINVAL;
}
kfree(data);
data=(char*)kmalloc(sizeof(char)*(count+1),GFP_KERNEL);
if(!data)
{
return -ENOMEM;
}
copy_from_user(data,buffer,count+1);
return count;
}
static struct file_operations chr_fops={ //基本函数入口点的结构体
.owner=THIS_MODULE,
.read=test_read,
.write=test_write,
.open=test_open,
.release=test_release,
};
static struct class *fs_class;//创建一个
static int __init test_init(void)
{
int res;
printk("this is skull device\n");
res=register_chrdev(fs_major,DEVICE_NAME,&chr_fops); //其中fs_major为主设备号,chr_fops 为基本函数入口
if(res<0)
{
printk("can't get major name!\n");
return res;
}
if(fs_major == 0)//如果主设备号初始化是0,则为其自动分配主设备号。
{
fs_major=res;
}
fs_class=class_create(THIS_MODULE,DEVICE_NAME); //THIS_MODULE,它的定义如下是#define THIS_MODULE (&__this_module),
device_create(fs_class,NULL,MKDEV(fs_major,0),NULL,DEVICE_NAME); //__this_module是一个struct module变量,代表当前模块
printk("initialized\n");
return 0;
}
static void __exit test_exit(void)
{
unregister_chrdev(fs_major,DEVICE_NAME);
device_destroy(fs_class,MKDEV(fs_major,0));//删除节点设备;MKDEV(fs_major,0)为通过主从设备号得到dev_t
class_destroy(fs_class);//注销类
printk("it's over now\n");
}
module_init(test_init);//调用rmmod fs.ko 卸载时会调用该接口
module_exit(test_exit);//调用insmod fs.ko 进行驱动模块加载时会调用该接口
//以下信息不是必需的
MODULE_AUTHOR("czn911");//作者信息
MODULE_DESCRIPTION("TQ2440 SKULL");//相关描述
MODULE_LICENSE("GPL");//遵守的协议
THIS_MODULE,它的定义如下是#define THIS_MODULE (&__this_module),__this_module是一个struct module变量,代表当前模块
错误列举:
error: implicit declaration of function 'class_device_create'
error: implicit declaration of function 'class_device_destroy'
原因:
class_device_create 和 class_device_destroy 是最期版本的API
现在已经改成device_create 和 device_destroy表当前模块,
编译错误:error: expected '=', ',', ';', 'asm' or '__attribute__' before... error: expected declaration specifiers or '...' before xxx
原因:有可能是你头文件的包含的顺序需要调换一下,具体参考:http://blog.csdn.net/xuyunzhang/article/details/6286873
Makefile程序
KERNELDIR=/opt/EmbedSky/linux-2.6.30.4/
PWD:=$(shell pwd)
INSTALLDIR=$(PWD)
CC=arm-linux-gcc
obj-m:=fs.o
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.c *.markers *.order *.symvers
.PHONY:modules clean
testing.c测试程序
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<linux/ioctl.h>
int main()
{
int fd,i,nwrite,nread;
char *buf="hello\n";
char read_buf[6]={0};
fd=open("/dev/FS",O_RDWR);
if(fd<0)
{
perror("open");
exit(1);
}
else
{
printf("open success\n");
}
nwrite=write(fd,buf,strlen(buf));
printf("the num write_to_kernel is: %d\n",nwrite);
if(nwrite<0)
{
perror("write");
exit(1);
}
nread=read(fd,read_buf,6);
printf("the num read_from_kernel is: %d\n",nread);
if(nread<0)
{
perror("read");
exit(1);
}
else
{
printf("read is %s\n",read_buf);
}
close(fd);
exit(0);
}
make后将会由fs.c 生成fs.ko文件
在用过arm-linux-gcc testint.c -o testing 生成testing可执行文件,注意这里要将testing的权限修改成777
然后通过tftp或者其他方式正这两个文件传输至开发板上
在执行insmod fs.ko 后,将会在/dev/ 目录下看到 设备文件FS ,这说明设备驱动已经加载好了,并且分配了设备号
执行./testing 就可以看到内存读写结果啦。
以上是我作为一个菜鸟对我目前所学习的一些理解,欢迎大家指正。
以下是我参考的一些资料链接,感谢他们的无私分享
http://blog.163.com/njut_wangjian/blog/static/16579642520121022112940349/
http://blog.csdn.net/xuyunzhang/article/details/6286873
http://blog.csdn.net/wzws45/article/details/5948308
http://www.embedu.org/Column/Column476.htm