Linux设备驱动之一 ---- 驱动的框架及其操作流程

来源:互联网 发布:168套优化重组2017答案 编辑:程序博客网 时间:2024/06/05 17:45
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
即可看到


0 0
原创粉丝点击