例程代碼路徑:ELF 1開(kāi)發(fā)板資料包3-例程源碼3-2 驅(qū)動(dòng)例程源碼3_內(nèi)核空間與用戶(hù)空間的數(shù)據(jù)拷貝copy_form_user
在copy_to_user.c源碼的基礎(chǔ)上添加device_write函數(shù)的實(shí)現(xiàn),重命名為copy_form_user.c
(一)定義變量
#define DEVICE_NAME "copy_form_user" ?// 設(shè)備名稱(chēng) static char user_buffer[BUFFER_SIZE] = ""; |
(二)在device_write()函數(shù)添加拷貝操作,用戶(hù)空間使用write函數(shù)時(shí),會(huì)進(jìn)入此函數(shù)。
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { ????????ssize_t bytes_written = 0; // 在這里處理設(shè)備寫(xiě)入的操作 ????????printk(KERN_INFO "This is device_write.n"); ? ????????if (*offset >= BUFFER_SIZE) ????????????????return -ENOSPC; ?????????if (*offset + length > BUFFER_SIZE) ?????????????????length = BUFFER_SIZE - *offset; ?????????if (copy_from_user(user_buffer + *offset, buffer, length)) ?????????????????return -EFAULT; ?????????*offset += length; ?????????bytes_written = length; ?????????printk(KERN_INFO "Received from user: %s", user_buffer); ? ?????????return bytes_written; } |
offset參數(shù)表示當(dāng)前文件位置的偏移量。它用于跟蹤讀取或?qū)懭氩僮髟谖募械奈恢谩?/p>
對(duì)于device_write()函數(shù)來(lái)說(shuō),offset參數(shù)用于指示應(yīng)寫(xiě)入數(shù)據(jù)的起始位置。根據(jù)需要,可以在函數(shù)內(nèi)部修改該偏移量,以便在下一次寫(xiě)操作時(shí)從適當(dāng)?shù)奈恢瞄_(kāi)始寫(xiě)入。
在上述示例中,首先執(zhí)行寫(xiě)操作,并使用offset參數(shù)作為起始位置。然后,通過(guò)將length添加到offset上來(lái)更新偏移量,以便在下一次寫(xiě)操作時(shí)從正確的位置開(kāi)始。
完整的copy_to_user.c示例源碼
#include <linux/module.h> ??????// 包含模塊相關(guān)函數(shù)的頭文件 #include <linux/fs.h> ??????????// 包含文件系統(tǒng)相關(guān)函數(shù)的頭文件 #include <linux/uaccess.h> ?????// 包含用戶(hù)空間數(shù)據(jù)訪(fǎng)問(wèn)函數(shù)的頭文件 #include <linux/cdev.h> ????????//包含字符設(shè)備頭文件 #include <linux/device.h> #include <linux/uaccess.h> #define DEVICE_NAME "copy_form_user" ?// 設(shè)備名稱(chēng) static dev_t dev_num; ??//分配的設(shè)備號(hào) struct ?cdev my_cdev; ?????????//字符設(shè)備指針 int major; ?//主設(shè)備號(hào) int minor; ?//次設(shè)備號(hào) static struct class *my_class; static struct device *my_device; ? #define BUFFER_SIZE 1024 static char kernel_buffer[BUFFER_SIZE] = "Hello, User! This is kernel_buffer!"; static char user_buffer[BUFFER_SIZE] = ""; ? static int device_open(struct inode *inode, struct file *file) { // 在這里處理設(shè)備打開(kāi)的操作 printk(KERN_INFO "This is device_open.n"); ????return 0; } ? static int device_release(struct inode *inode, struct file *file) { // 在這里處理設(shè)備關(guān)閉的操作 printk(KERN_INFO "This is device_release.n"); ????return 0; } static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { ????????ssize_t bytes_read = 0; // 在這里處理設(shè)備讀取的操作 ????????printk(KERN_INFO "This is device_read.n"); ? ????????if (*offset >= BUFFER_SIZE) ????????????????return 0; ????????if (*offset + length > BUFFER_SIZE) ????????????????length = BUFFER_SIZE - *offset; ????????if (copy_to_user(buffer, kernel_buffer + *offset, length)) ????????????????return -EFAULT; ????????*offset += length; ????????bytes_read = length; ????????return bytes_read; ? ? } ? static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { ???ssize_t bytes_written = 0; ? // 在這里處理設(shè)備寫(xiě)入的操作 ????????printk(KERN_INFO "This is device_write.n"); ? ????????if (*offset >= BUFFER_SIZE) ????????????????return -ENOSPC; ?????????if (*offset + length > BUFFER_SIZE) ?????????????????length = BUFFER_SIZE - *offset; ?????????if (copy_from_user(user_buffer + *offset, buffer, length)) ?????????????????return -EFAULT; ?????????*offset += length; ?????????bytes_written = length; ?????????printk(KERN_INFO "Received from user: %s", user_buffer); ? ?????????return bytes_written; } ? static struct file_operations fops = { ????.owner = THIS_MODULE, ????.open = device_open, ????.release = device_release, ????.read = device_read, ????.write = device_write, }; static int __init mydevice_init(void) { ????int ret; ? ????// 在這里執(zhí)行驅(qū)動(dòng)程序的初始化操作 ? ????// 注冊(cè)字符設(shè)備驅(qū)動(dòng)程序 ????ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME); ????if (ret < 0) { ????????printk(KERN_ALERT "Failed to allocate device number: %dn", ret); ????????return ret; } ???major=MAJOR(dev_num); ???minor=MINOR(dev_num); printk(KERN_INFO "major number: %dn",major); printk(KERN_INFO "minor number: %dn",minor); ? my_cdev.owner = THIS_MODULE; ????????cdev_init(&my_cdev,&fops); ????????cdev_add(&my_cdev,dev_num,1); ? ???????// 創(chuàng)建設(shè)備類(lèi) ????my_class = class_create(THIS_MODULE, "my_class"); ????if (IS_ERR(my_class)) { ????????pr_err("Failed to create classn"); ????????return PTR_ERR(my_class); } ??// 創(chuàng)建設(shè)備節(jié)點(diǎn)并關(guān)聯(lián)到設(shè)備類(lèi) ????my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME); ????if (IS_ERR(my_device)) { ????????pr_err("Failed to create devicen"); ????????class_destroy(my_class); ????????return PTR_ERR(my_device); ????} ???????????printk(KERN_INFO "Device registered successfully.n"); ????return 0; } static void __exit mydevice_exit(void) { // 在這里執(zhí)行驅(qū)動(dòng)程序的清理操作 // 銷(xiāo)毀設(shè)備節(jié)點(diǎn) ?device_destroy(my_class, MKDEV(major, minor)); // 銷(xiāo)毀設(shè)備類(lèi) ?class_destroy(my_class); // 刪除字符設(shè)備 ????cdev_del(&my_cdev); ????// 注銷(xiāo)字符設(shè)備驅(qū)動(dòng)程序 ????unregister_chrdev(0, DEVICE_NAME); ? ????printk(KERN_INFO "Device unregistered.n"); } ? module_init(mydevice_init); module_exit(mydevice_exit); ? MODULE_LICENSE("GPL"); ?????// 指定模塊的許可證信息 MODULE_AUTHOR("Your Name"); // 指定模塊的作者信息 MODULE_DESCRIPTION("A simple character device driver"); // 指定模塊的描述信息 |
編譯
復(fù)制7.4.2驅(qū)動(dòng)中的Makefile文件,將其中的copy_to_user.o修改為copy_form_user.o,效果如下:
. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi elf@ubuntu:~/work/test/03_內(nèi)核空間與用戶(hù)空間的數(shù)據(jù)拷貝/copy_form_user$ make |
將驅(qū)動(dòng)模塊編譯成.ko并傳到開(kāi)發(fā)板中。
編寫(xiě)測(cè)試應(yīng)用源碼copy_form_user
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <errno.h> #include <fcntl.h> #include <string.h> ? #define DEV_NAME "/dev/copy_form_user" #define BUFFER_SIZE 1024 ? int main(int argc, char *argv[]) { int reg; int fd = 0; char *write_buffer="Hello,kernel!This is user_buffer!"; ? ?fd = open (DEV_NAME, O_RDWR); ?if (fd < 0) { ?perror("Open "DEV_NAME" Failed!n"); ?exit(1); ?} ? if (write(fd, write_buffer, strlen(write_buffer)) < 0) { ?????????printf("Failed to write to device file: %sn", DEV_NAME); ?????????close(fd); ?????????exit(1); ?} ? ?printf("Wrote to device file: %sn", DEV_NAME); ?close(fd); ?return 0; ?} |
編譯應(yīng)用
. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi ? elf@ubuntu:~/work/test/03_內(nèi)核空間與用戶(hù)空間的數(shù)據(jù)拷貝/copy_form_user_app$ $CC copy_form_user.c -o copy_form_user |
將編譯好的應(yīng)用程序發(fā)送到開(kāi)發(fā)板中
測(cè)試
root@ELF1:~# insmod copy_form_user.ko major number: 248 minor number: 0 Device registered successfully. root@ELF1:~# ./copy_form_user This is device_open. This is device_write. Received from user: Hello,kernel!This is user_buffer!Wrote to device file: /dev/copy_f orm_user This is device_release. root@ELF1:~# rmmod copy_form_user.ko Device unregistered. |
可以看到運(yùn)行測(cè)試程序后,可以看到驅(qū)動(dòng)里把用戶(hù)空間傳進(jìn)去的字符串打印了出來(lái)。