樹莓派驅動開發簡單案例完整過程(動態加載驅動)

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!

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