I.驱动程序的编写
#include
#include
#include
#include
static int led_drv_open(struct inode *inode, struct file *file)
{
printk("this is a led_drv_open\n");
return 0;
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("this is a led_drv_write\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_drv_open,
.write = led_drv_write,
};
static int led_drv_init(void)
{
register_chrdev(111, "led_drv", &led_drv_fops); // 注册, 告诉内核
return 0;
}
static void led_drv_exit(void)
{
unregister_chrdev(111, "led_drv"); // 卸载
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
注:
1>在这个驱动程序中,设备号为静态分配,设备节点手动创建。
2>在register_chrdev()这个函数中当其主设备号为0时,表示动态分配,其余情况为静态分配。
其静态分配是根据Documentation/devices.txt,确定一个没有使用的主设备号,当然也可以在单板中执行cat /proc/devices
看一下哪些字符设备号是没有使用的,然后再进行静态分配。
3>关于register_chrdev()函数的解释
/***************************register_chrdev()函数********************************************
/**
* register_chrdev() - Register a major number for character devices.
* @major: major device number or 0 for dynamic allocation
* @name: name of this range of devices
* @fops: file operations associated with this devices
*
* If @major == 0 this functions will dynamically allocate a major and return
* its number.
*
* If @major > 0 this function will attempt to reserve a device with the given
* major number and will return zero on success.
*
* Returns a -ve errno on failure.
*
* The name of this device has nothing to do with the name of the device in
* /dev. It only helps to keep track of the different owners of devices. If
* your module name has only one type of devices it's ok to use e.g. the name
* of the module here.
*
* This function registers a range of 256 minor numbers. The first minor number
* is 0.
*/
************************register_chrdev()函数***********************************************/
II>驱动程序的Makefile
ifneq ($(KERNELRELEASE),)
obj-m:=led_drv.o
else
# KERNELDIR:=/lib/modules/$(shell uname -r)/build
# KERNELDIR:=/lib/modules/2.6.30.4/build
KERNELDIR:=/home/ubuntu/workdir/code/linux-2.6.30.4
PWD :=$(shell pwd)
default:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
endif
III>编译驱动
在当前我们写的这个驱动下,make之后,即可看到led_drv.ko文件,然后拷贝到Linux的nfs目录下。
注:这个nfs目录是我在Linux搭建的NFS服务器,这用来在开发板和Linux之间传输文件用的。
IV>加载模块
在开发板的一段,我们在其nfs挂载点上看到led_drv.ko文件,我的开发板的nfs挂载点是/nfsroot/目录,
在这个目录下执行
insmod led_drv.ko
然后执行
cat /proc/devices
即可看我们刚才加载的驱动模块
111 led_drv.ko
注:在这里,我当时出现了一个小问题就是:
解决的办法:
在内核目录下执行 make menuconfig ----> General setup ----> Local version - append to kernel release 中添加 -EmbedSky
然后保存退出。
再重新编译内核和驱动。再insmod就可以看到我们将加载的模块了。
注:在此对网友的回答表示感谢!
V.测试程序的编写
#include
#include
#include
#include
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/led_drv", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
write(fd,&val,4);
}
VI.测试程序的Makefile
led_drv_test:led_drv_test.o
arm-linux-gcc led_drv_test.o -o led_drv_test
led_drv_test.o:led_drv_test.c
arm-linux-gcc -c led_drv_test.c -o led_drv_test.o
clean:
rm -rf led_drv_test.o led_drv_test
VII.编译测试程序
在测试程序的目录中,执行make命令,即可得到led_drv_test的可执行文件,将其拷贝到nfs目录下。
在运行前我们需要做一件事,就是手动创建设备节点。因为我们在驱动程序中没有实现自动创建设备节点,所以设备节点的创建
就需要我们手动完成了。命令如下:
mknod /dev/led_drv c 111 0
注:关于mknod的用法如下:
mknod filename type major minor
filename :设备文件名
type :设备文件类型
major :主设备号
minor:次设备号
例:mknod serial0 c 100 0
VIII.运行测试程序
./led_drv_test
即可看到
关注我,分享好玩科技,探索未知世界