在ubuntu下编写验证字符设备驱动
并移植到arm开发板上
1,准备工作
uname -r 查看电脑版本信息
apt-get install linux-source 安装相应版本的linux内核
2,编写驱动程序
Global CharDev.c
/*GlobalCharDev.c*/#include#include#include#include
#define DEV_NAME "GlobalChar"
static ssize_t GlobalRead(struct file *, char *, size_t, loff_t *);static ssize_t GlobalWrite(struct file *, const char *, size_t,loff_t *);static int char_major = 0;static int GlobalData = 0; /*"GlobalChar"设备的全局变量*/
/*初始化字符设备驱动的 file_operations 结构体*/
struct file_operations globalchar_fops ={
.read=GlobalRead,
.write=GlobalWrite
};/*模块初始化*/
static int __init GlobalChar_init(void)
{intret;
ret= register_chrdev(char_major, DEV_NAME, &globalchar_fops);/*注册设备驱动,_driver_char_misc.c 第290行参考*/
if(ret < 0)
printk(KERN_ALERT"GlobalChar Reg Fail\n");else{
printk(KERN_ALERT"GlobalChar Reg Success\n");
char_major=ret;
printk(KERN_ALERT"Major = %d\n", char_major);
}returnret;
}/*模块卸载函数*/
static void __exit GlobalChar_exit(void)
{
unregister_chrdev(char_major, DEV_NAME);/*注销设备驱动*/
return;
}/*模块驱动读函数*/
static ssize_t GlobalRead(struct file *file, char *buf, size_t len, loff_t *off)
{if (copy_to_user(buf, &GlobalData ,sizeof(int)))
{/*从内核复制 GlobalData 到用户空间*/
return -EFAULT;
}return sizeof(int);
}/*模块驱动写函数*/
static ssize_t GlobalWrite(struct file *file, const char *buf, size_t len, loff_t *off)
{if (copy_from_user(&GlobalData, buf, sizeof(int)))
{/*从用户复制 GlobalData 到内核*/
return -EFAULT;
}return sizeof(int);
}
module_init(GlobalChar_init);
module_exit(GlobalChar_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongjin");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m :=GlobalCharDev.oelse# KERNELDIR?= /lib/modules/$(shell uname -r)/build
KERNELDIR?= /usr/src/linux-headers-$(shell uname -r) //这两个都可以
PWD :=$(shell pwd)default:
$(MAKE)-C $(KERNELDIR) M=$(PWD) modules
clean:
rm-rf rm -rf *.ko *.mod* *.o* *.sy*endif
理解:
pwd--> 驱动文件目录
kerneldir --> 内核源码目录
default --> 表示到内核源码目录中去编译pwd下的驱动文件
——————————————————————————————————————————————————————
make 编译
root@ubuntu:/home/arm/data/char_driver# make
make-C /usr/src/linux-headers-4.4.0-31-generic M=/home/arm/data/char_driver modules
make[1]: 正在进入目录 `/usr/src/linux-headers-4.4.0-31-generic' CC [M] /home/arm/data/char_driver/GlobalCharDev.o
Building modules, stage2.
MODPOST1modules
LD [M]/home/arm/data/char_driver/GlobalCharDev.ko
make[1]:正在离开目录 `/usr/src/linux-headers-4.4.0-31-generic'
出现Global CharDev.ko文件
2,insmod Global CharDev.ko 将模块加入内核
3,cat /proc/devices 查看驱动设备
4,mknod /dev/GlobalChar c 247 0 根据相应的设备号,建立设备节点。
5,测试文件
/*GlobaiCharText.c 测试文件*/#include#include#include#include#include
#define DEV_NAME "/dev/GlobalChar"
intmain()
{intfd, num;/*打开设备文件*/fd= open(DEV_NAME, O_RDWR, S_IRUSR |S_IWUSR);if(fd < 0)
{
printf("Open Device Fail!\n");return -1;
}/*读取当前设备数值*/read(fd,&num, sizeof(int));
printf("The GlobalChar is %d\n", num);
printf("Please input a numble written to GlobalChar:");
scanf("%d", &num);/*写入新的数值*/write(fd,&num, sizeof(int));/*重新读取数值*/read(fd,&num, sizeof(int));
printf("The GlobalChar is %d\n", num);
close(fd);return 0;
}
gcc -o GlobalCharText GlobalCharText.c 编译出可执行文件
执行:
root@ubuntu:/home/arm/data/char_driver# ./a.outThe GlobalCharis 0Please input a numble written to GlobalChar:111The GlobalCharis 111
——————————————————————————————————————————————————————————————————————
通过NFS我们可以建立共享目录,将编写好的驱动加载到arm板,当然也需要配置环境变量。
1,驱动文件:需要将Make file中KERNLDIR 改成 自己下载内核的地址,如:
KERNELDIR ?= /home/arm/linux-4.4
2,测试文件:理所当然我们需要使用交叉编译去编译出可执行文件。
注意:首先我们要知道自己制作的做小系统是采用静态编译还是动态编译,我的采用静态编译
1,静态:
2,动态:
需要在制作最小系统时,在 /lib 下加入所需的动态交叉编译库(所选交叉编译工具目录下的链接库),但是我在制作randisk的过程中,提示内存不足,暂没查找其原因。
如果在静态根文件系统内使用动态编译链所编译的elf,会提示:-sh:./test:no found (这里 not found 指的是 链接库)
测试:
卸载:
1,删除 /dev 下的设备节点
rm /dev/GlobalChar
2,卸载驱动
rmmod GlopbalCharDev.ko
出现问题:
——————————————————————————————————————————————————————
参考:
http://tieba.baidu.com/p/3645403366
https://blog.csdn.net/Ultraman_hs/article/details/53239455
解决移植到arm上不兼容的问题
https://blog.csdn.net/zqj6893/article/details/48439711
解决驱动卸载问题