日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

嵌入式Linux设备驱动程序:编写内核设备驱动程序

發布時間:2023/11/28 生活经验 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌入式Linux设备驱动程序:编写内核设备驱动程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

嵌入式Linux設備驅動程序:編寫內核設備驅動程序

Embedded Linux device drivers: Writing a kernel device driver

編寫內核設備驅動程序

最終,當您用盡了之前所有的用戶空間選項后,您將發現自己必須編寫一個設備驅動程序來訪問連接到設備上的硬件。字符驅動程序是最靈活的,應該能滿足你90%的需求;網絡驅動程序適用于使用網絡接口,而塊驅動程序用于大容量存儲。編寫內核驅動程序的任務很復雜,超出了本文的范圍。最后有一些參考資料可以幫助你。概述一下與驅動程序交互時可用的選項,這是一個通常不會涉及的主題,并向您展示角色設備驅動程序的基本知識。

設計字符驅動接口

主字符驅動程序接口基于字節流,就像使用串行端口一樣。然而,許多設備并不符合這種描述:例如,機器人手臂的控制器需要功能來移動和旋轉每個關節。幸運的是,除了讀寫之外,還有其他與設備驅動程序通信的方法:

ioctl:ioctl函數允許您將兩個參數傳遞給您的驅動程序,這兩個參數可以具有您喜歡的任何含義。按照慣例,第一個參數是一個命令,它選擇驅動程序中幾個函數中的一個,第二個參數是指向結構的指針,它充當輸入和輸出參數的容器。一個像畫布這樣的程序可以讓你設計任何一個空白的界面。當驅動程序和應用程序緊密鏈接并由同一個團隊編寫時,這種情況很常見。但是,ioctl在內核中是不推薦使用的,而且您會發現很難在上游使用ioctl的任何驅動程序得到接受。內核維護者不喜歡ioctl,因為它使內核代碼和應用程序代碼過于相互依賴,而且很難在內核版本和體系結構中保持兩者同步。

sysfs:這是現在的首選方式,前面描述的GPIO接口就是一個很好的例子。它的優點是,只要為文件選擇描述性名稱,它就有點自文檔化。它也是可編寫腳本的,因為文件內容通常是文本字符串。另一方面,如果需要一次更改多個值,則每個文件都必須包含一個值,這使得實現原子性變得很困難。相反,ioctl在單個函數調用中傳遞結構中的所有參數。

mmap:通過將內核內存映射到用戶空間,繞過內核,可以直接訪問內核緩沖區和硬件寄存器。內核和DMA可能仍然需要處理一些代碼中斷。uio文檔中有更多的uio驅動程序,例如,在文檔中有更多的uio。

sigio:您可以使用名為kill_fasync()的內核函數從驅動程序發送信號,以通知應用程序輸入準備就緒或接收到中斷等事件。按照慣例,使用SIGIO信號,但可以是任何信號。您可以在UIO驅動程序drivers/UIO/UIO.c和RTC驅動程序drivers/char/RTC.c中看到一些示例。主要問題是很難在用戶空間中編寫可靠的信號處理程序,因此它仍然是一個很少使用的工具。 debugfs:這是另一個偽文件系統,它將內核數據表示為文件和目錄,類似于proc和sysfs。主要區別在于debugfs不能包含系統正常運行所需的信息;它只包含調試和跟蹤信息。它掛載為mount-t debugfs debug/sys/kernel/debug。內核文檔documentation/filesystems中對debugfs有很好的描述/調試文件.txt.

proc:proc文件系統對于所有新代碼都是不推薦使用的,除非它與進程相關,這是文件系統最初的目的。但是,您可以使用proc發布您選擇的任何信息。而且,與sysfs和debugfs不同,它可用于非GPL模塊。

netlink:這是一個socket協議族。AFüNETLINK創建一個將內核空間鏈接到用戶空間的套接字。它最初是為了讓網絡工具可以與Linux網絡代碼通信來訪問路由表和其他細節。udev也使用它將事件從內核傳遞到udev,這在一般設備驅動程序中很少使用。

在內核源代碼中有許多前面提到的文件系統的例子,您可以為您的驅動程序代碼設計真正有趣的接口。唯一的普遍規則是最小驚奇原則。換言之,使用驅動程序的應用程序編寫者應該發現,一切都以邏輯方式工作,沒有任何怪癖或怪癖。

設備驅動程序的剖析 ‘

現在是時候通過查看一個簡單的設備驅動程序的代碼來繪制一些線程。下面是一個名為dummy的設備驅動程序,它創建了四個通過

dev/dummy0 to /dev/dummy3 .

驅動程序的完整源代碼如下:您將在

MELP/chapter_09/dummy-driver :

#include #include #include #include #include #define DEVICE_NAME “dummy”#define MAJOR_NUM 42#define NUM_DEVICES 4static struct class *dummy_class;static int dummy_open(struct inode *inode, struct file *file){ pr_info("%sn", func); return 0;}static int dummy_release(struct inode *inode, struct file *file){ pr_info("%sn", func); return 0;}static ssize_t dummy_read(struct file *file, char *buffer, size_t length, loff_t * offset){ pr_info("%s %un", func, length); return 0;}static ssize_t dummy_write(struct file *file, const char *buffer, size_t length, loff_t * offset){ pr_info("%s %un", func, length); return length;}struct file_operations dummy_fops = { .owner = THIS_MODULE, .open = dummy_open, .release = dummy_release, .read = dummy_read, .write = dummy_write,};int __init dummy_init(void){ int ret; int i; printk(“Dummy loadedn”); ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &dummy_fops); if (ret != 0) return ret; dummy_class = class_create(THIS_MODULE, DEVICE_NAME); for (i = 0; i < NUM_DEVICES; i++) { device_create(dummy_class, NULL, MKDEV(MAJOR_NUM, i), NULL, “dummy%d”, i); } return 0;}void __exit dummy_exit(void){ int i; for (i = 0; i < NUM_DEVICES; i++) { device_destroy(dummy_class, MKDEV(MAJOR_NUM, i)); } class_destroy(dummy_class); unregister_chrdev(MAJOR_NUM, DEVICE_NAME); printk(“Dummy unloadedn”);}module_init(dummy_init);module_exit(dummy_exit);MODULE_LICENSE(“GPL”);MODULE_AUTHOR(“Chris Simmonds”);MODULE_DESCRIPTION(“A dummy driver”);

At the end of the code, the macros called module_init and module_exit specify the functions to be called when the module is loaded and unloaded. The three macros named MODULE_* add some basic information about the module, which can be retrieved from the compiled kernel module using the modinfo

When the module is loaded, the dummy_init() function is called. You can see the point at which it becomes a character device when is makes the call to register_chrdev , passing a pointer to struct file_operations , which contains pointers to the four functions that the driver implements. While register_chrdev tells the kernel that there is a driver with a major number of 42, it doesn’t say anything about the class of driver, and so it will not create an entry in /sys/class . Without an entry in /sys/class , the device manager cannot create device nodes. So, the next few lines of code create a device class, dummy and four devices of that class called dummy0 to dummy3 . The result is that the /sys/class/dummy directory is created when the driver is initialized, containing subdirectories dummy0 to dummy3 . Each of the subdirectories contains a file, dev , with the
major and minor numbers of the device. This is all that a device manager needs to create device nodes: /dev/dummy0 to /dev/dummy3 .

The dummy_exit function has to release the resources claimed by dummy_init , which here means freeing up the device class and major number.

The file operations for this driver are implemented by dummy_open() , dummy_read(), dummy_write(), and dummy_release() and are called when a user space program calls open(2), read(2), write(2), and close(2). They just print a kernel message so that you can see that they were
called. You can demonstrate this from the command line using the echo command:

echo hello > /dev/dummy0

dummy_open

dummy_write 6

dummy_release

In this case, the messages appear because I was logged on to the console, and kernel messages are printed to the console by default. If you are not logged onto the console, you can still see the kernel messages using the command dmesg .

The full source code for this driver is less than 100 lines, but it is enough to illustrate how the linkage between a device node and driver code works, how the device class is created, allowing a device manager to create device nodes automatically when the driver is loaded, and how the data is moved between user and kernel spaces. Next, you need to build it.

Compiling kernel modules

At this point, you have some driver code that you want to compile and test on your target system. You can copy it into the kernel source tree and modify makefiles to build it, or you can compile it as a module out of tree. Let’s start by building out of tree.

You need a simple makefile which uses the kernel build system to do the hard work:

LINUXDIR := $(HOME)/MELP/build/linux

obj-m := dummy.o

all:
make ARCH=arm CROSS_COMPILE=arm-cortex_a8-linux-gnueabihf-

         -C

(LINUXDIR)M=(LINUXDIR) M=(LINUXDIR)M=(shell pwd)

clean:

make -C (LINUXDIR)M=(LINUXDIR) M=(LINUXDIR)M=(shell pwd) clean

Set LINUXDIR to the directory of the kernel for your target device that you will be running the module on. The obj-m := dummy.o code will invoke the kernel build rule to take the source file, dummy.c , and create kernel module, dummy.ko . I will show you how to load kernel modules in the next section.

If you want to build a driver in the kernel source tree, the procedure is quite simple. Choose a directory appropriate to the type of driver you have. The driver is a basic character device, so I would put dummy.c in drivers/char . Then, edit the makefile in the directory, and add a line to build the driver
unconditionally as a module, as follows:

obj-m += dummy.o

Or add the following line to build it unconditionally as a built-in:

obj-y += dummy.o

If you want to make the driver optional, you can add a menu option to
the Kconfig file and make the compilation conditional on the configuration
option, as I described in Chapter 4, Configuring and Building the Kernel, in the section, Understanding kernel configuration .

Loading kernel modules
You can load, unload, and list modules using the simple insmod, lsmod, and rmmod commands. Here they are shown loading the dummy driver:

# insmod /lib/modules/4.8.12-yocto standard/kernel/drivers/dummy.ko
# lsmod

Tainted: G

dummy 2062 0 - Live 0xbf004000 (O)

# rmmod dummy

If the module is placed in a subdirectory in /lib/modules/ , you can create a modules dependency database using the command, depmod -a:

# depmod -a

# ls /lib/modules/4.8.12-yocto-standard

kernel modules.alias modules.dep modules.symbols

The information in the module.* files is used by the modprobe command to locate a module by name rather than the full path. modprobe has many other features, which are described on the manual page modprobe(8) .

The next article in this series will describe how to discover the system’s
hardware configuration.

總結

以上是生活随笔為你收集整理的嵌入式Linux设备驱动程序:编写内核设备驱动程序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文字幕一区不卡 | 日本一本高清视频 | 午夜视频免费在线观看 | 国久久| 国产乱子伦精品视频 | 中文字幕一区二区三区人妻 | 色婷婷av久久久久久久 | 久久新视频| 精品久久一二三区 | 久久国产成人精品 | 欧美在线视频第一页 | 中文字幕码精品视频网站 | 驯服少爷漫画免费观看下拉式漫画 | 国产精品99久久久久久大便 | 肉感丰满的av演员 | 大尺度舌吻呻吟声 | 久久免费成人 | 8x国产一区二区三区精品推荐 | 国产精品无码电影 | 1024精品一区二区三区日韩 | 国产一线二线在线观看 | 中文写幕一区二区三区免费观成熟 | 少妇视频一区 | 精品一区二区三区在线观看 | 国产精品播放 | 国产免费二区 | 欧美日韩乱国产 | 高h捆绑拘束调教小说 | 亚洲作爱网 | 欧美a∨亚洲欧美亚洲 | 欧美一级一区 | 欧美自拍一区 | 午夜xxx | 国产一区二区免费在线观看 | 裸体男女树林做爰 | 日韩欧美中文字幕在线播放 | 欧美一级一区 | 午夜av激情| 免费av国产 | 成人av免费网址 | 91视频高清| 日韩av线上 | 女女综合网 | 欧美色图俺去了 | 夜色福利| 国产成人一区二区三区 | 久久久久夜夜夜精品国产 | 国产免费自拍视频 | 欧美日韩综合一区 | 女人18毛片水真多 | 国产精品人成 | 欧美国产中文 | 久久伊人操 | 中文字幕在线一区 | 亚洲无卡 | free性护士vidos猛交 | 国产伦精品一区二区三区精品 | 国产乱xxⅹxx国语对白 | 欧美自拍视频在线观看 | 欧美高清hd18日本 | 天天综合精品 | 色噜噜综合网 | 免费在线观看不卡av | 免费黄色一级 | 在线不卡日本 | 欧美性猛交99久久久久99按摩 | 天堂资源中文在线 | 91在线视频免费 | 色综合五月天 | 欧美做受高潮 | 欧美九九九 | 色呦呦视频 | 成人在线视频网址 | 欧美三级黄色 | 日韩字幕在线 | 成人av一级 | 在线不卡| www.久久av | 亚洲色成人网站www永久四虎 | 久久免费在线观看视频 | 亚洲一区二区三区四区视频 | 免费av一级 | 蜜臀少妇久久久久久久高潮 | xxxx日韩| 最新中文字幕在线 | 天天天天 | 色婷婷伊人 | 99免费国产 | 国产在线观看免费视频软件 | 成全世界免费高清观看 | 久久久精品一区二区涩爱 | 少妇人妻一区二区 | 丁香激情网 | 亚州| 国产一区二区视频免费观看 | 日韩一级片免费在线观看 | 色哟哟一区二区 | 大学生高潮无套内谢视频 | 国产97在线观看 |