国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

LDD學習筆記 -- Linux字符設備驅動

這篇具有很好參考價值的文章主要介紹了LDD學習筆記 -- Linux字符設備驅動。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

字符驅動程序用于與Linux內核中的設備進行交互;
字符設備指的是像內存區(qū)域這樣的硬件組件,通常稱為偽設備;
用戶空間應用程序通常使用open read write等系統調用與這些設備通信;

虛擬文件系統 VFS

把用戶空間的系統調用連接到設備驅動的系統調用實現方法上。
內核的虛擬文件系統 virtual file system,在內核空間
設備驅動需要使用內核的API向虛擬文件系統注冊

設備號

Major numbers(指示特定的驅動) + Minor numbers(表示指定的設備文件)

設備創(chuàng)建時候在VFS注冊設備號,虛擬文件系統,將設備文件的設備號與驅動程序列表進行比較,選擇正確的驅動程序,并將用戶請求連接到對應驅動程序的文件操作方法。

相關Kernel APIs

kernel functions and data structures(Creation) (Deletion) kernel header file
alloc_chrdev_region() unregister_chrdev_region() include/linux/fs.h
cdev_init() cdev_add() cdev_del() include/linux/cdev.h
device_creat() class_creat() device_destory() class_destory include/linux/device.h
copy_to_user() copy_from_user() include/linux/uaccess.h
VFS structure definitions include/linux/cdev.h

動態(tài)申請設備號

alloc_chrdev_region() 可以動態(tài)申請主設備號,保證唯一性,傳輸設備號(dev_t [u32])地址和次設備號起始(一般0)和個數。

dev_t device_number;  //32bit
int minor_no = MINOR(device_number);  //后20bit  `kdev_t.h`
int major_no = MAJOR(device_number);  //前12bit

MKDEV(int major, int minor);

動態(tài)創(chuàng)建設備文件

當收到uevent,udev根據uevent內存儲的細節(jié)在dev目錄下創(chuàng)建設備文件。

class_create :在sysf中創(chuàng)建一個目錄/sys/Class/<your_class_name>
device_create:在上面目錄下使用設備名創(chuàng)建一個子目錄/sys/Class/<your_class_name>/<your_device_name> /dev 這里的dev文件存儲設備名主副設備號等
udev:用戶空間的應用,動態(tài)創(chuàng)建設備文件/sys/Class/<your_class_name>/<your_device_name> /dev --> dev/your_device_name

內核空間和用戶空間的數據交換

用戶空間的指針不是完全可信的,用戶地址空間有時可能無效,虛擬內存管理器可以交換出這些內存位置。
內核級代碼不能直接引用用戶級內存指針;
使用內核數據復制工具copy_to_user copy_from_user。工具會檢查用戶空間指針是否有效

系統調用方法

read

用戶級進程執(zhí)行read系統調用從文件中讀取。文件可以是普通文件,也可以是一個設備文件(處理具體設備)。

例如前面的偽字符設備,有一塊內存數組(設備內存buffer)。當用戶程序在該設備文件上發(fā)出read系統調用時,應該將數據從設備buffer傳到用戶buffer。該數據拷貝發(fā)生在內核端到用戶端。

write

將數據從用戶空間復制到內核空間,
用戶程序想把一些數據寫入設備內存buffer。

lseek

改變f_pos(struct file)變量的位置,將文件位置指針向前/向后移動。

寫一個偽字符設備驅動

  1. 動態(tài)申請設備號
  2. 創(chuàng)建cdev結構體變量和file_operiations結構體變量
  3. 使用fops初始化字符設備結構體變量
  4. 向內核VFS注冊設備
  5. 實現file operiation的方法
  6. 初始化file operiation變量
  7. 創(chuàng)建設備文件 class_create() device_create()
  8. 驅動清理函數功能實現
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <uapi/asm-generic/errno-base.h>

#define DEV_MEM_SIZE    512

/* pseudo device's memory */
char device_buffer[DEV_MEM_SIZE];

/* This hold the device number */
dev_t device_number;

/* Cdev variable */
struct cdev pcd_cdev;

loff_t pcd_llseek(struct file *filp, loff_t offset, int whence)
{
        pr_info("%s\n", __func__);
        loff_t temp;

        switch (whence)
        {
                case SEEK_SET:
                        if ((offset > DEV_MEM_SIZE) || (offset < 0))
                                return -EINVAL;
                        filp->f_pos = offset;
                        break;
                case SEEK_CUR:
                        temp = filp->f_pos + offset;
                        if ((temp > DEV_MEM_SIZE) || (offset < 0))
                                return -EINVAL;
                        filp->f_pos = temp;
                        break;
                case SEEK_END:
                        temp = DEV_MEM_SIZE + offset;
                        if ((temp > DEV_MEM_SIZE) || (offset < 0))
                                return -EINVAL;
                        filp->f_pos = temp;
                        break;
                
                default:
                        return -EINVAL;

        }

        pr_info("New value of the file position = %lld\n", filp->f_pos);

        return filp->f_pos;
        // return 0;

}

ssize_t pcd_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
{
        pr_info("%s :Read requested for %zu bytes\n", __func__, count);

        if((*f_pos + count) > DEV_MEM_SIZE)
                count = DEV_MEM_SIZE - *f_pos;

        if(copy_to_user(buff, &device_buffer[*f_pos], count)){
                return -EFAULT;
        }

        *f_pos += count;
        pr_info("Number of bytes successful read = %zu\n", count);
        pr_info("Update file position = %lld\n", *f_pos);

        return count;
}
ssize_t pcd_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos)
{
        pr_info("%s :Write requested for %zu bytes, current file position = %lld\n", __func__, count, *f_pos);

        if((*f_pos + count) > DEV_MEM_SIZE)
                count = DEV_MEM_SIZE - *f_pos;

        if(!count)
                return -ENOMEM;

        if(copy_from_user(&device_buffer[*f_pos], buff, count)){
                return -EFAULT;
        }

        *f_pos += count;
        pr_info("Number of bytes successful writtens = %zu\n", count);
        pr_info("Update file position = %lld\n", *f_pos);
        return count;
}
int pcd_open(struct inode *inode, struct file *filp)
{
        pr_info("%s\n", __func__);
        return 0;
}
int pcd_release(struct inode *inode, struct file *filp)
{
        pr_info("%s\n", __func__);
        return 0;
}


/* file operations variable */
struct file_operations pcd_fops = {
        .open = pcd_open,
        .write = pcd_write,
        .read = pcd_read,
        .llseek = pcd_llseek,
        .release = pcd_release,
        .owner = THIS_MODULE
};

struct class *class_pcd;
struct device *device_pcd;

static int __init pcd_driver_init(void)
{
        pr_info("pcd_driver_init\n");
        
        /* 1. Dynamically allocate a device number */
        alloc_chrdev_region(&device_number, 0, 1, "pcd");

        pr_info("Device number <major>:<minor> = %d:%d\n", MAJOR(device_number), MINOR(device_number));

        /* 2. Initialize the cdev structure with fops */
        cdev_init(&pcd_cdev, &pcd_fops);

        /* 3. Register a device(cdev structure) with VFS */
        pcd_cdev.owner = THIS_MODULE;
        cdev_add(&pcd_cdev, device_number, 1);

        /* creat device class under /sys/class / */
        class_pcd = class_create(THIS_MODULE, "pcd_class");

        /* populate the sysfs with device information */
        device_pcd = device_create(class_pcd, NULL, device_number, NULL, "pcd");

        pr_info("Module init was successful\n");

        return 0;
}

/* This is module clean-up entry point */
static void __exit pcd_driver_exit(void)
{
        pr_info("my hello module exit\n");
        device_destroy(class_pcd, device_number);
        class_destroy(class_pcd);
        cdev_del(&pcd_cdev);
        unregister_chrdev_region(device_number, 1);
        pr_info("module unloaded\n");
}

/* registration */
module_init(pcd_driver_init);
module_exit(pcd_driver_exit);

/* This is description information about the module */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("NAME");
MODULE_DESCRIPTION("A pseudo device driver");

在主機上測試pcd(HOST)

使用echo 命令測試向PCD寫數據
使用cat命令測試從PCD讀數據

LDD學習筆記 -- Linux字符設備驅動,Linux,學習,筆記,linux
LDD學習筆記 -- Linux字符設備驅動,Linux,學習,筆記,linux

在目標板上測試pcd(TARGET)

需要在用戶空間寫一個應用程序(測試應用)來測試字符設備驅動程序。使用對應目標板的編譯工具鏈編譯.c文件成目標板上的可執(zhí)行文件,有沒有.exe后綴都可,自己知道就行。

arm-buildroot-linux-gnueabihf-gcc ./pcd_drv_test.c -o pcd_dev_test

將上面設備驅動編譯出的目標板的.ko文件和我們的測試應用文件都放到目標板上。


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

/*
 * ./pcd_drv_test -w hello fpn233~
 * ./pcd_drv_test -r
 */
int main(int argc, char **argv)
{
	int fd;
	char buf[512];
	int len;
	
	/* 1. 判斷參數 */
	if (argc < 2) 
	{
		printf("Usage: %s -w <string>\n", argv[0]);
		printf("       %s -r\n", argv[0]);
		return -1;
	}

	/* 2. 打開文件 */
	fd = open("/dev/pcd", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file /dev/pcd\n");
		return -1;
	}

	/* 3. 寫文件或讀文件 */
	if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
	{
		len = strlen(argv[2]) + 1;
		len = len < 512 ? len : 512;
		write(fd, argv[2], len);
	}
	else
	{
		len = read(fd, buf, 512);		
		buf[1023] = '\0';
		printf("APP read : %s\n", buf);
	}
	
	close(fd);
	
	return 0;
}

LDD學習筆記 -- Linux字符設備驅動,Linux,學習,筆記,linux

LDD學習筆記 -- Linux字符設備驅動,Linux,學習,筆記,linux文章來源地址http://www.zghlxwxcb.cn/news/detail-787395.html

到了這里,關于LDD學習筆記 -- Linux字符設備驅動的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 嵌入式Linux(8):字符設備驅動--注冊字符類設備

    雜項設備 注冊雜項設備: 注銷雜項設備: 字符類設備 文件:include/linux/cdev.h 步驟流程: 定義一個cdev結構體。 使用cdev_init函數初始化cdev結構體成員變量。 參數: 第一個:要初始化的cdev結構體 第二個:文件操作集: cdev-ops = fops;//實際就是把文件操作集寫ops 使用cdev_add函數

    2023年04月22日
    瀏覽(24)
  • Linux 驅動之字符設備

    Linux 驅動之字符設備

    什么是設備號 Linux 規(guī)定每一個字符設備或者塊設備都必須有一個專屬的設備號。一個設備號由主設備號和次設備號組成。主設備號用來表示某一類驅動,如鼠標,鍵盤都可以歸類到 USB 驅動中。而次設備號是用來表示這個驅動下的各個設備。比如第幾個鼠標,第幾個鍵盤等。

    2024年02月16日
    瀏覽(21)
  • 【嵌入式Linux學習筆記】platform設備驅動和input子系統

    【嵌入式Linux學習筆記】platform設備驅動和input子系統

    對于Linux這種龐大的操作系統,代碼重用性非常重要,所以需要有相關的機制來提升效率,去除重復無意義的代碼,尤其是對于驅動程序,所以就有了platform和INPUT子系統這兩種工作機制。 學習視頻地址:【正點原子】STM32MP157開發(fā)板 platform 驅動框架分為總線、設備和驅動???/p>

    2024年02月07日
    瀏覽(26)
  • Linux 驅動之高級字符設備

    Linux 驅動之高級字符設備

    什么是IO呢? IO 的英文全稱是 input 和output,翻譯過來就是輸入和輸出。 在馮.諾依曼結構中,將計算機分成分為5個部分: 運算器、控制器、存儲器、輸入設備、輸出設備 。其中輸入設備指的是向計算機輸入數據或者信息,如鼠標,鍵盤都是輸入設備。輸出設備指的是用于接收

    2023年04月14日
    瀏覽(31)
  • Linux -- 字符設備驅動--LED的驅動開發(fā)(初級框架)

    Linux -- 字符設備驅動--LED的驅動開發(fā)(初級框架)

    看原理圖確定引腳,確定引腳輸出什么電平才能點亮 / 熄滅 LED 看主芯片手冊,確定寄存器操作方法:哪些寄存器?哪些位?地址是? 編寫驅動:先寫框架,再寫硬件操作的代碼 注意 :在芯片手冊中確定的寄存器地址被稱為 物理地址 ,在 Linux 內核中無法直接使用。 需要使

    2024年04月28日
    瀏覽(27)
  • Linux下字符設備驅動開發(fā)以及流程介紹

    Linux下字符設備驅動開發(fā)以及流程介紹

    首先我們介紹一下什么是字符設備,然后講解一下字符設備開發(fā)的具體的流程,分別詳細介紹每一個流程中涉及到的結構體以及知識點,最后我們編寫代碼實現字符設備的開發(fā)以及測試。 Linux內核設計哲學是把所有的東西都抽象成文件進行訪問,這樣對設備的訪問都是通過文

    2024年02月01日
    瀏覽(37)
  • Linux字符設備驅動(設備文件,用戶空間與內核空間進行數據交互,ioctl接口)

    Linux字符設備驅動(設備文件,用戶空間與內核空間進行數據交互,ioctl接口)

    在Linux系統中“一切皆文件”,上一篇講述了cdev結構體就描述了一個字符設備驅動,主要包括設備號和操作函數集合。但是要怎么操作這個驅動呢?例如,使用open()該打開誰,read()該從哪讀取數據等等。所以就需要創(chuàng)建一個設備文件來代表設備驅動。 應用程序要操縱外部硬件

    2024年02月12日
    瀏覽(27)
  • 【linux驅動開發(fā)】在linux內核中注冊一個雜項設備與字符設備以及內核傳參的詳細教程

    【linux驅動開發(fā)】在linux內核中注冊一個雜項設備與字符設備以及內核傳參的詳細教程

    開發(fā)環(huán)境: windows + ubuntu18.04 + 迅為rk3568開發(fā)板 相較于字符設備,雜項設備有以下兩個優(yōu)點: 節(jié)省主設備號:雜項設備的主設備號固定為 10,在系統中注冊多個 misc 設備驅動時,只需使用子設備號進行區(qū)分即可。 使用簡單:相比如普通的字符設備驅動, misc驅動只需要將基本信

    2024年01月21日
    瀏覽(20)
  • Linux驅動開發(fā)筆記(四):設備驅動介紹、熟悉雜項設備驅動和ubuntu開發(fā)雜項設備Demo

    Linux驅動開發(fā)筆記(四):設備驅動介紹、熟悉雜項設備驅動和ubuntu開發(fā)雜項設備Demo

    若該文為原創(chuàng)文章,轉載請注明原文出處 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533 紅胖子網絡科技博文大全:開發(fā)技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續(xù)更新中… 上一篇:《Linux驅動開發(fā)筆記(三

    2024年02月05日
    瀏覽(50)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包