目錄
一、驅(qū)動程序編寫流程
二、代碼編寫
2.1 驅(qū)動程序hello_drv.c
2.2 測試程序
2.3 編寫驅(qū)動程序的Makefile
三、上機實驗
3.1?NFS 掛載
3.2 測試示例
一、驅(qū)動程序編寫流程
-
構(gòu)造file_operations結(jié)構(gòu)體
-
在里面填充open/read/write/ioctl成員
-
注冊file_operations結(jié)構(gòu)體?int major = register_chrdev(0, "name", &fops);
-
入口函數(shù):調(diào)用regiister_chrdev
-
出口函數(shù):調(diào)用unregiister_chrdev
-
輔助信息: class_create/class_destroy? ?device_create/device_destroy
總結(jié):應(yīng)用程序調(diào)用open/read/write/ioctl,驅(qū)動程序就給你提供對應(yīng)的open/read/write/ioctl,只不過驅(qū)動程序的這些函數(shù)為了便于管理,故把函數(shù)放在file_operations結(jié)構(gòu)體里面,通過 register_chrdev函數(shù)把結(jié)構(gòu)體告訴內(nèi)核,并注冊字符設(shè)備驅(qū)動程序。驅(qū)動程序里面有個入口函數(shù),相當于main函數(shù),是裝載驅(qū)動程序時調(diào)用的函數(shù),在入口函數(shù)中注冊,把結(jié)構(gòu)體放到chrdevs數(shù)組里面來,出口函數(shù)中反注冊,就是把結(jié)構(gòu)體拿掉,在卸載驅(qū)動程序時調(diào)用的函數(shù)。 ?
二、代碼編寫
2.1 驅(qū)動程序hello_drv.c
參考 driver/char 中的程序,包含頭文件,寫框架,傳輸數(shù)據(jù):
- 驅(qū)動中實現(xiàn) open, read, write, release, APP 調(diào)用這些函數(shù)時,都打印內(nèi)核信息
- APP 調(diào)用 write 函數(shù)時,傳入的數(shù)據(jù)保存在驅(qū)動中? ?
- APP 調(diào)用 read 函數(shù)時,把驅(qū)動中保存的數(shù)據(jù)返回給 APP? ?
- 需要注意的是,驅(qū)動程序和應(yīng)用程序之間數(shù)據(jù)傳遞要使用copy_from_user(hello_buf, buf, len)和copy_to_user(buf, hello_buf, len)
-
class_create和device_create這兩個函數(shù)為我們創(chuàng)建了設(shè)備節(jié)點、主次設(shè)備號等輔助信息就不用手動創(chuàng)建設(shè)備節(jié)點了 mknod /dev/xyz c 245 0
-
class_create(THIS_MODULE, "hello_class"),創(chuàng)建類:為這個模塊創(chuàng)建類,類名叫hello_class
-
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"),在類下面創(chuàng)建設(shè)備信息:在hello_class下創(chuàng)建設(shè)備,沒有父親NULL,主次設(shè)備號,無私有數(shù)據(jù)NULL,格式hello根據(jù)這些信息,系統(tǒng)會為我們創(chuàng)建設(shè)備節(jié)點,設(shè)備節(jié)點名字是/dev/hello,和上面的類名無關(guān)
-
device_destroy(hello_class, MKDEV(major, 0))銷毀hello_class類下面的這個設(shè)備(由主次設(shè)備號確定)
-
class_destroy(hello_class)銷毀hello_class類
#include "asm/cacheflush.h"
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
static struct class *hello_class;
static int major;
static unsigned char hello_buf[100];
static int hello_open (struct inode *node, struct file *filp)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
unsigned long len = size > 100 ? 100 : size;
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
copy_to_user(buf, hello_buf, len);
return len;
}
static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
unsigned long len = size > 100 ? 100 : size;
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
copy_from_user(hello_buf, buf, len);
return len;
}
static int hello_release (struct inode *node, struct file *filp)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* 1. create file_operations */
static const struct file_operations hello_drv = {
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
.open = hello_open,
.release = hello_release,
};
/* 2. register_chrdev */
/* 3. entry function */
static int hello_init(void)
{
major = register_chrdev(0, "100ask_hello", &hello_drv);
hello_class = class_create(THIS_MODULE, "hello_class");
if (IS_ERR(hello_class)) {
printk("failed to allocate class\n");
return PTR_ERR(hello_class);
}
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
return 0;
}
/* 4. exit function */
static void hello_exit(void)
{
device_destroy(hello_class, MKDEV(major, 0));
class_destroy(hello_class);
unregister_chrdev(major, "100ask_hello");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
2.2 測試程序
測試程序要實現(xiàn)讀、寫功能:
./hello_test /dev/xxx abcdef // 把字符串“abcdeft”發(fā)給驅(qū)動程序
./hello_test /dev/xxx // 把驅(qū)動中保存的字符串讀回來
hello_drv_test.c源碼如下
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/* 寫: ./hello_test /dev/xxx 100ask
* 讀: ./hello_test /dev/xxx
*/
int main(int argc, char **argv)
{
int fd;
int len;
char buf[100];
if (argc < 2)
{
printf("Usage: \n");
printf("%s <dev> [string]\n", argv[0]);
return -1;
}
// open
fd = open(argv[1], O_RDWR);
if (fd < 0)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
if (argc == 3)
{
// write
len = write(fd, argv[2], strlen(argv[2])+1);
printf("write ret = %d\n", len);
}
else
{
// read
len = read(fd, buf, 100);
buf[99] = '\0';
printf("read str : %s\n", buf);
}
// close
close(fd);
return 0;
}
2.3 編寫驅(qū)動程序的Makefile
驅(qū)動程序中包含了很多頭文件,這些頭文件來自內(nèi)核,不同的 ARM 板它的某些頭文件可能不同。所以編譯驅(qū)動程序時,需要指定板子所用的內(nèi)核的源碼路徑。要編譯哪個文件?這也需要指定,設(shè)置 obj-m 變量即可怎么把.c 文件編譯為驅(qū)動程序.ko?這要借助內(nèi)核的頂層 Makefile。
本驅(qū)動程序的 Makefile 內(nèi)容如下:
KERN_DIR = /home/me/Linux-4.9.88 :指定內(nèi)核目錄
先設(shè)置好交叉編譯工具鏈,編譯好你的板子所用的內(nèi)核,然后修改 Makefile指定內(nèi)核源碼路徑,最后即可執(zhí)行make命令編譯驅(qū)動程序和測試程序。?
三、上機實驗
3.1?NFS 掛載
我們是在 Ubuntu 中編譯程序,但是需要在 ARM 板子上測試。所以需要把程序放到 ARM 板子上。啟動單板后,可以通過 NFS 掛載 Ubuntu 的某個目錄,訪問該目錄中的程序。
ifconfig eth0 192.168.5.9 //靜態(tài)配置開發(fā)板ip地址
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt //掛載到開發(fā)板上的mnt目錄下
echo "7 4 1 7" > /proc/sys/kernel/printk //打開內(nèi)核打印信息
?
3.2 測試示例
首先在開發(fā)板的mnt目錄下查看文件是否掛載成功,當前目錄下以及有了Ubuntu編譯好的驅(qū)動程序和測試文件
insmod hello_drv.ko // 安裝驅(qū)動程序
ls /dev/hello -l // 驅(qū)動程序會生成設(shè)備節(jié)點
./hello_drv_test // 查看測試程序的用法
?顯示已載入系統(tǒng)的模塊
查看測試程序用法,并寫入字符串"abcdef"后讀出,測試結(jié)果如下:?文章來源:http://www.zghlxwxcb.cn/news/detail-635196.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-635196.html
到了這里,關(guān)于【IMX6ULL驅(qū)動開發(fā)學(xué)習】01.編寫第一個hello驅(qū)動+自動創(chuàng)建設(shè)備節(jié)點(不涉及硬件操作)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!