2018-2019-1 20165226_20165310_20165315 實驗四 外設驅動程序設計

2018-2019-120165226_20165310_20165315 實驗四 外設驅動程序設計

目錄


1、任務一
2、任務二
3、實驗過程當中遇到的問題及解決
4、實驗感想node

1、任務一


(一)要求
一、學習資源中全課中的「hqyj.嵌入式Linux應用程序開發標準教程.pdf」中的第十一章
二、提交康奈爾筆記的照片linux

(二)結果
shell

返回目錄函數

2、任務二


(一)要求
在Ubuntu完成資源中全課中的「hqyj.嵌入式Linux應用程序開發標準教程.pdf」中的第十一章的test試驗
提交編譯,加載模塊,卸載模塊,測試運行的截圖(要多張,全屏,體現學號信息)學習

(二)實驗步驟:
一、編寫代碼測試

/* test_drv.c */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#define TEST_DEVICE_NAME "test_dev"
#define BUFF_SZ 1024
/*全局變量*/
static struct cdev test_dev;
unsigned int major =0;
static char *data = NULL;
/*讀函數*/
static ssize_t test_read(struct file *file,
char *buf, size_t count, loff_t *f_pos)
{
int len;
if (count < 0 )
{
return -EINVAL;
}
len = strlen(data);
count = (len > count)?count:len;
if (copy_to_user(buf, data, count)) /* ?內核??的數????用戶??*/
{
return -EFAULT;
}
return count;
}
/*寫函數*/
static ssize_t test_write(struct file *file, const char *buffer,
size_t count, loff_t *f_pos)
{
if(count < 0)
{
return -EINVAL;
}
memset(data, 0, BUFF_SZ);
count = (BUFF_SZ > count)?count:BUFF_SZ;
if (copy_from_user(data, buffer, count)) /* 將用戶緩衝的數據複製到內核空間*/
{
return -EFAULT;
}
return count;
}
/*打開函數*/
static int test_open(struct inode *inode, struct file *file)
{
printk("This is open operation\n");
/* 分配並初始化緩衝區*/
data = (char*)kmalloc(sizeof(char) * BUFF_SZ, GFP_KERNEL);
if (!data)
{
return -ENOMEM;
}
memset(data, 0, BUFF_SZ);
return 0;
}
/*關閉函數*/
static int test_release(struct inode *inode,struct file *file)
{
printk("This is release operation\n");
if (data)
{
kfree(data); /* 釋放緩衝區*/
data = NULL; /* 防止出現野指針*/
}
return 0;
}
/* 建立、初始化字符設備,而且註冊到系統*/
static void test_setup_cdev(struct cdev *dev, int minor,
struct file_operations *fops)
{
int err, devno = MKDEV(major, minor);
cdev_init(dev, fops);
dev->owner = THIS_MODULE;
dev->ops = fops;
err = cdev_add (dev, devno, 1);
if (err)
{
printk (KERN_NOTICE "Error %d adding test %d", err, minor);
}
}
/* 虛擬設備的 file_operations 結構 */
static struct file_operations test_fops =
{
.owner = THIS_MODULE,
.read = test_read,
.write = test_write,
.open = test_open,
.release = test_release,
};
/*模塊註冊入口*/
int init_module(void)
{
int result;
dev_t dev = MKDEV(major, 0);
if (major)
{/* 靜態註冊一個設備,設備號先前指定好,並設定設備名,用cat /proc/devices 來查看 */
result = register_chrdev_region(dev, 1, TEST_DEVICE_NAME);
}
else
{
result = alloc_chrdev_region(&dev, 0, 1, TEST_DEVICE_NAME);
}
if (result < 0)
{
printk(KERN_WARNING "Test device: unable to get major %d\n", major);
return result;
}
test_setup_cdev(&test_dev, 0, &test_fops);
printk("The major of the test device is %d\n", major);
return 0;
}
/*卸載模塊*/
void cleanup_module(void)
{
cdev_del(&test_dev);
unregister_chrdev_region(MKDEV(major, 0), 1);
printk("Test device uninstalled\n");
}

二、編譯代碼ui

  • 經過make運行makefile以實現test_drv.c代碼的編譯
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build /*內核代碼編譯路徑*/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
obj-m := test_drv.o /* 將生成的模塊爲 test_drv.ko*/
endif

三、驅動模塊加載和卸載命令行

  • 加載腳本test_drv_load
#!/bin/sh
# 驅動模塊名稱
module="test_drv"
# 設備名稱。在/proc/devices 中出現
device="test_dev"
# 設備文件的輸性
mode="664"
group="david"
# 刪除已存在的設備節點
rm -f /dev/${device}
# 加載驅動模塊
/sbin/insmod -f ./$module.ko $* || exit 1
# 查到設備的主設備號
major=`cat /proc/devices | awk "\\$2==\"$device\" {print \\$1}"`
# 建立設備文件節點
mknod /dev/${device} c $major 0
# 設置設備文件屬性
chgrp $group /dev/${device}
chmod $mode /dev/${device}
  • 卸載腳本test_drv_unload
#!/bin/sh
module="test_drv"
device="test_dev"
# 卸載驅動模塊
/sbin/rmmod $module $* || exit 1
# 刪除設備文件
rm -f /dev/${device}
exit 0

四、運行test.c測試代碼對驅動程序進行測試設計

/* test.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define TEST_DEVICE_FILENAME "/dev/test_dev" /* 設備文件名*/
#define BUFF_SZ 1024 /* 緩衝大小 */
int main()
{
int fd, nwrite, nread;
char buff[BUFF_SZ]; /*緩衝區*/
/* 打開設備文件 */
fd = open(TEST_DEVICE_FILENAME, O_RDWR);
if (fd < 0)
{
perror("open");
exit(1);
}
do
{
printf("Input some words to kernel(enter 'quit' to exit):");
memset(buff, 0, BUFF_SZ);
if (fgets(buff, BUFF_SZ, stdin) == NULL)
{
perror("fgets");
break;
}
buff[strlen(buff) - 1] = '\0';
if (write(fd, buff, strlen(buff)) < 0) /* 向設備寫入數據 */
{
perror("write");
break;
}
if (read(fd, buff, BUFF_SZ) < 0) /* 從設備讀取數據 */
{
perror("read");
break;
}
else
{
printf("The read string is from kernel:%s\n", buff);
}
} while(strncmp(buff, "quit", 4));
close(fd);
exit(0);
}

(三)運行結果指針

  • 在虛擬設備驅動源碼目錄下編譯並加載驅動模塊。
$ make clean;make
$ ./test_drv_load


  • 編譯並運行測試程序
$ gcc –o test test.c
$ ./test

  • 卸載驅動程序
$ ./test_drv_unload

返回目錄

3、實驗過程當中遇到的問題及解決


  • 問題1:Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev

  • 問題1解決方案:經過網上查找,輸入命令行sudo apt install libelf-dev

  • 問題2:報錯function-declaration

  • 問題2解決方案:將test_drv.c中的copy_from_user語句改爲raw_copy_from_user,編譯成功

返回目錄

4、實驗感想


  • 本次實驗學習了初步學習了嵌入式Linux設備驅動的開發。
  • 使用了康奈爾筆記,在線索/疑問以及總結方面獲得更好鍛鍊。
    返回目錄
相關文章
相關標籤/搜索