字符设备驱动基础篇4——字符设备驱动读写接口的操作实践
生活随笔
收集整理的這篇文章主要介紹了
字符设备驱动基础篇4——字符设备驱动读写接口的操作实践
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
以下內(nèi)容源于朱有鵬嵌入式課程的學(xué)習(xí),如有侵權(quán),請告知刪除。
參考資料:http://www.cnblogs.com/biaohc/p/6575074.html。
一、細(xì)節(jié)
1、自動分配主設(shè)備號
- 注冊函數(shù)傳參時,第一個參數(shù)填0,表示讓內(nèi)核自動分配主設(shè)備號,返回值為主設(shè)備號。注銷時,注銷剛才返回的主設(shè)備號。
2、設(shè)備文件的創(chuàng)建
- 設(shè)備文件的關(guān)鍵信息是:設(shè)備號 = 主設(shè)備號 + 次設(shè)備號,使用ls -l去查看設(shè)備文件,就可以得到設(shè)備文件對應(yīng)的主次設(shè)備號。
- 使用“mknod /dev/xxx c 主設(shè)備號 次設(shè)備號”來創(chuàng)建設(shè)備文件,其中xxx表示設(shè)備文件名,c表示字符設(shè)備;
- xxx不能用vim來打開,可以用ls /dev/xxx -l查看。
二、讀寫接口的操作實踐
(1)應(yīng)用(用戶空間)和驅(qū)動(內(nèi)核空間)之間的數(shù)據(jù)交換
- copy_from_user,將數(shù)據(jù)從用戶空間復(fù)制到內(nèi)核空間;
- copy_to_user,將數(shù)據(jù)從內(nèi)核空間;
- copy_from_user:如果成功復(fù)制則返回0,如果不成功復(fù)制則返回尚未成功復(fù)制的剩下的字節(jié)數(shù);
- 復(fù)制機制、mmap的映射兩者比較:復(fù)制時內(nèi)核空間和用戶空間的地址不一樣,效率低。
(2)代碼
應(yīng)用層代碼app.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> //這是應(yīng)用層#define FILE "/dev/test" // 剛才手工mknod創(chuàng)建的設(shè)備文件名,問題是mknod需要輸入主設(shè)備號,和自動獲取不背離嗎?char buf[100];int main(void) {int fd = -1;fd = open(FILE, O_RDWR);//這里的open,對應(yīng)的是驅(qū)動文件中的.open指定的函數(shù)if (fd < 0){printf("open %s error.\n", FILE);return -1;}printf("open %s success..\n", FILE);// 讀寫文件write(fd, "helloworld2222", 14);read(fd, buf, 100);printf("讀出來的內(nèi)容是:%s.\n", buf);// 關(guān)閉文件close(fd);return 0; }
驅(qū)動文件module_test.c
#include <linux/module.h> // module_init module_exit #include <linux/init.h> // __init __exit #include <linux/fs.h> #include <asm/uaccess.h>#define MYNAME "testchar"int mymajor; //內(nèi)核自動分配的主設(shè)備號 char kbuf[100]; //內(nèi)核空間(即驅(qū)動空間,畢竟內(nèi)核和驅(qū)動屬于同一層)的bufstatic int test_chrdev_open(struct inode *inode, struct file *file) {// 這個函數(shù)中真正應(yīng)該放置的是打開這個設(shè)備的硬件操作代碼部分// 但是現(xiàn)在暫時我們寫不了這么多,所以用一個printk打印個信息來做代表。printk(KERN_INFO "test_chrdev_open\n");return 0; }static int test_chrdev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_release\n");return 0; }//讀函數(shù),即從內(nèi)核空間(驅(qū)動空間)讀取數(shù)據(jù)到用戶空間 ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) {int ret = -1;printk(KERN_INFO "test_chrdev_read\n");//將內(nèi)容從內(nèi)核空間(驅(qū)動空間)讀取到用戶空間//返回值為0說明讀取成功,讀取不成功時返回值是剩余沒有讀取的字節(jié)數(shù)ret = copy_to_user(ubuf, kbuf, count);if (ret){printk(KERN_ERR "copy_to_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_to_user success..\n");return 0; }// 寫函數(shù) //1、將應(yīng)用層的數(shù)據(jù)先復(fù)制到內(nèi)核中 //2、然后將之以正確的方式寫入硬件完成操作。 static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { //此函數(shù)前三個參數(shù),對應(yīng)應(yīng)用層的write函數(shù)的三個參數(shù)?int ret = -1;printk(KERN_INFO "test_chrdev_write\n");// 1、使用該函數(shù)將應(yīng)用層傳過來的ubuf中的內(nèi)容拷貝到驅(qū)動空間中的一個buf中//memcpy(kbuf, ubuf); // 不行,因為用戶空間和內(nèi)核空間,兩者不在一個地址空間中ret = copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR "copy_from_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_from_user success..\n");// 2、真正的驅(qū)動中,數(shù)據(jù)從應(yīng)用層復(fù)制到驅(qū)動中后,我們就要根據(jù)這個數(shù)據(jù)//去寫硬件完成硬件的操作。所以這下面就應(yīng)該是操作硬件的代碼return 0; }// 自定義一個file_operations結(jié)構(gòu)體變量,并且去填充 static const struct file_operations test_fops = {.owner = THIS_MODULE, // 慣例,直接寫即可.open = test_chrdev_open, // 將來應(yīng)用open打開這個設(shè)備時實際調(diào)用的就是這個.open對應(yīng)的函數(shù).release = test_chrdev_release, .write = test_chrdev_write,.read = test_chrdev_read, };// 模塊安裝函數(shù) static int __init chrdev_init(void) { printk(KERN_INFO "chrdev_init helloworld init\n");// 在module_init宏調(diào)用的函數(shù)中去注冊字符設(shè)備驅(qū)動// major傳0進(jìn)去表示要讓內(nèi)核幫我們自動分配一個合適的空白的沒被使用的主設(shè)備號// 內(nèi)核如果成功分配就會返回分配的主設(shè)備好;如果分配失敗會返回負(fù)數(shù)mymajor = register_chrdev(0, MYNAME, &test_fops);if (mymajor < 0){printk(KERN_ERR "register_chrdev fail\n");return -EINVAL;}printk(KERN_INFO "register_chrdev success... mymajor = %d.\n", mymajor);return 0; }// 模塊載函數(shù) static void __exit chrdev_exit(void) {printk(KERN_INFO "chrdev_exit helloworld exit\n");// 在module_exit宏調(diào)用的函數(shù)中去注銷字符設(shè)備驅(qū)動unregister_chrdev(mymajor, MYNAME);}module_init(chrdev_init); module_exit(chrdev_exit);// MODULE_xxx這種宏作用是用來添加模塊描述信息 MODULE_LICENSE("GPL"); // 描述模塊的許可證 MODULE_AUTHOR("aston"); // 描述模塊的作者 MODULE_DESCRIPTION("module test"); // 描述模塊的介紹信息 MODULE_ALIAS("alias xxx"); // 描述模塊的別名信息總結(jié)
以上是生活随笔為你收集整理的字符设备驱动基础篇4——字符设备驱动读写接口的操作实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ie8 升级页面html,ie7浏览器怎
- 下一篇: MyBatis【钢镚核恒】