树莓派驱动开发简单案例完整过程(动态加载驱动)

1.下载树莓派os镜像:https://www.raspberrypi.org/downloads/raspbian/ 

2.使用命令:uname -a 查看树莓派内核:Linux raspberrypi 4.19.118-v7+ #1311 SMP Mon Apr 27 14:21:24 BST 2020 armv7l GNU/Linux

3.一般使用是树莓派镜像中不含有内核源码,因此要下载树莓派内核源码:在目录/usr/src 下执行命令:sudo apt-get install raspberrypi-kernel-headers

******* 将会下载到与uname -a 查看树莓派内核版本号一致的内核源码。如果不一致,可能无法用于内核驱动的使用。

4.编写驱动helloworld.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define HELLOWORLD_MAJOR      200           //主设备号
#define HELLOWORLD_NAME     "helloworld"    //名字

static char readbuf[30]; /*读缓冲 */
static char writebuf[30];  /* 写缓冲 */
static char kerneldata[] = {"Hello World!"};


static int helloworld_open(struct inode *inode, struct file *filp)
{
   	printk("helloworld_open\r\n");
    return 0;
}

static int helloworld_release(struct inode *inode, struct file *filp)
{
   	printk("helloworld_release\r\n");
    return 0;   
}

static ssize_t helloworld_read(struct file *filp, __user char *buf, size_t count,
			loff_t *ppos)
{ 
    int ret  = 0;
    printk("helloworld_read\r\n");
    memcpy(readbuf, kerneldata, sizeof(kerneldata));
    ret = copy_to_user(buf, readbuf, count);

    return 0;  
}

static ssize_t helloworld_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
    int ret = 0;
    printk("helloworld_write\r\n");
    ret = copy_from_user(writebuf, buf, count);
    if(ret == 0) {
        printk("kernel recevdata:%s\r\n", writebuf);
    }

    return 0; 
}

/*
 * 字符设备 操作集合
 */
static struct file_operations helloworld_fops={
    .owner = THIS_MODULE,
    .open = helloworld_open,
    .release = helloworld_release,
    .read = helloworld_read,
    .write = helloworld_write,
};


static int __init helloworld_init(void)
{
    int ret = 0;
    printk("hello world init\r\n");

    /* 注册字符设备 */
    ret = register_chrdev(HELLOWORLD_MAJOR, HELLOWORLD_NAME, &helloworld_fops);
    if(ret < 0) {
        printk("helloworld init failed!\r\n");
    }

	return 0;
}

static void __exit helloworld_exit(void)
{
    printk("helloworld_exit\r\n");	
    /* 注销字符设备 */
    unregister_chrdev(HELLOWORLD_MAJOR, HELLOWORLD_NAME);

}

/*
 模块入口与出口
 */
module_init(helloworld_init);  /* 入口 */
module_exit(helloworld_exit);  /* 出口 */

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("changhaijun");


5.编写Makefile

ifneq ($(KERNELRELEASE),)
obj-m := helloworld.o
else  
KDIR := /usr/src/linux-headers-4.19.118-v7+/  #树莓派内核源码目录
PWD := $(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm *.o *.ko *.mod.c modules.order Module.symvers
.PHONY:clean
endif

6.将helloworld.c 和 Makefile 放在同一个目录下执行:make   生成.ko文件

7.加载驱动与卸载驱动

(1)动态加载驱动执行:inmod  helloworld.ko    查看驱动是否加载上执行命令:cat /proc/devices

(2)卸载驱动执行命令:rmmod helloworld.ko   查看驱动是否卸载执行命令:cat /proc/devices

8.手动创建设备节点执行命令:mknod /dev/helloworld  c 200  0        (c 表示字符设备)  查看是否创建:ls  /dev

9.编写应用程序helloworldApp.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd = 0;
    char *filename;
    char readbuf[30], writebuf[30];
    static char usrdata[] = {"user data!"};

    if(argc != 3) {
        printf("Error usage!\r\n");
        return -1;
    }

    filename = argv[1];

    fd = open(filename, O_RDWR);
    if(fd < 0 ) {
        printf("Can't open file %s\r\n", filename);
        return -1;
    }

    if(atoi(argv[2]) == 1){ /*  璇?*/
        /* read */
        ret = read(fd, readbuf, 13);
        if (ret < 0) {
            printf("read file %s failed!\r\n", filename);
        }
        else {
            printf("APP read data:%s\r\n", readbuf);
        }
    }

    /* write */
    if(atoi(argv[2]) == 2) { /* 鍐?*/ 
        memcpy(writebuf, usrdata, sizeof(usrdata));
        ret = write(fd, writebuf, 11);
        if (ret < 0) {
            printf("write file %s failed!\r\n", filename);
        }else {
            printf("APP writedata:%s\r\n", writebuf);
        }
    }

    /* close */
    ret = close(fd);
    if(ret < 0) {
        printf("close file %s falied!\r\n", filename);
    }

    return 0 ;

}

10.交叉编译工具编译应用程序helloworldApp.c

gcc -Wall -o helloworldApp helloworldApp.c  

 生成 helloworldApp

11.执行应用程序:./helloworldApp  /dev/helloworld 1    输出:APP read  data:Hello World!

     执行应用程序:./helloworldApp  /dev/helloworld 2    输出:APP writedata:user data!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章