????????對于字符設備驅動而言,當驅動模塊加載成功以后需要注冊字符設備,同樣,卸載驅動模?
塊的時候也需要注銷掉字符設備。字符設備的注冊和注銷函數原型如下所示 :
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)static inline void unregister_chrdev(unsigned int major, const char *name)
register_chrdev 函數用于注冊字符設備,此函數一共有三個參數,這三個參數的含義如下:
major: 主設備號, Linux 下每個設備都有一個設備號,設備號分為主設備號和次設備號兩部分
name:設備名字,指向一串字符串。
fops: 結構體 file_operations 類型指針,指向設備的操作函數集合變量。
unregister_chrdev 函數用戶注銷字符設備,此函數有兩個參數,這兩個參數含義如下:
major:要注銷的設備對應的主設備號。
name:要注銷的設備對應的設備名。
???????? 一般字符設備的注冊在驅動模塊的入口函數 xxx_init?中進行,字符設備的注銷在驅動模塊?
的出口函數 xxx_exit 中進行。
需要注意的是 register_chrdev 與 unregister_chrdev 函數在注冊字符設備驅動時,會將主設備號下的所有設備都注冊掉,即你無法再使用次設備號了,所以在后面的Linux內核中,這種方法已經被逐漸棄用了。
關于主設備號和次設備號:
??????? Linux 中每個設備都有一個設備號,設備號由主設備號和次設備號兩部分 組成,主設備號表示某一個具體的驅動,次設備號表示使用這個驅動的各個設備。 Linux 提供了 一個名為 dev_t 的數據類型表示設備號, dev_t 定義在文件 include/linux/types.h 里面。
????????dev_t 其實就是 unsigned int 類型,是一個 32 位的數據類型。這 32 位的數據構 成了主設備號和次設備號兩部分,其中高 12 位為主設備號,低 20 位為次設備號。因此 Linux 系統中主設備號范圍為 0~4095,所以在選擇主設備號的時候不要超過這個范圍。??
在選擇設備號時,我們需要先查看當前系統中已經有哪些設備號被占用
[root@luckfox ]# cat /proc/devices
Character devices:1 mem4 /dev/vc/04 tty4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx7 vcs10 misc13 input29 fb81 video4linux89 i2c90 mtd
116 alsa
128 ptm
136 pts
153 spi
180 usb
189 usb_device
226 drm
243 hidg
244 mpi
245 vcodec
246 mpp_service
247 rpmb
248 watchdog
249 iio
250 media
251 rtc
252 rk_dma_heap
253 ttyFIQ
254 gpiochip
......
我們需要在Character devices選擇一個沒有被占用的設備號,例如200
在設備注冊時,還需要有字符設備操作集,我們可以先按照最簡的方法實現
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h> //增加fs.h頭文件#define CHRDEVBASE_MAJOR 200 //主設備號
#define CHRDEVBASE_NAME "chrdevbase" //主設備號/* 打開設備 */
static int chrdevbase_open(struct inode *inode, struct file *filp)
{printk("chrdevbase_open\n");return 0;
}static int chrdevbase_release(struct inode *inode, struct file *filp)
{printk("chrdevbase_release\n");return 0;
}/* 從設備讀取 */
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{printk("chrdevbase_read\n");return 0;
}static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{printk("chrdevbase_write\n");return 0;
}/* 字符設備操作集 */
struct file_operations chrdevbase_fops =
{.owner = THIS_MODULE,.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write,};static int chrdevbase_init(void)
{int ret = 0;printk("chrdevbase_init\n");/*注冊字符設備*/ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(ret < 0){printk("chrdevbase init failed \r\n");}printk("register_chrdev\n");return 0;
}static void chrdevbase_exit(void)
{/*注銷字符設備*/unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);printk("unregister_chrdev\n");printk("chrdevbase_exit\n");
}/*模塊入口和出口
*/module_init(chrdevbase_init); /* 入口 */
module_exit(chrdevbase_exit); /* 出口 */// 必須添加的許可證聲明
MODULE_LICENSE("GPL"); // 使用 GPL 許可證
MODULE_AUTHOR("HYA"); // 可選(作者信息)
編譯源碼,將ko文件通過adb push到板端,加載模塊
經過下面的log可以看到,在設備注冊后,字符設備里就有了設備號為200的chrdevbase
同樣的,卸載模塊后,字符設備也被注銷了
[root@luckfox ]# insmod chrdevbase.ko
[root@luckfox ]#
[root@luckfox ]#
[root@luckfox ]# dmesg
[ 2255.299762] chrdevbase_init
[ 2255.299798] register_chrdev
[root@luckfox ]# [root@luckfox ]# cat /proc/devices
Character devices:1 mem4 /dev/vc/04 tty4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx7 vcs10 misc13 input29 fb81 video4linux89 i2c90 mtd
116 alsa
128 ptm
136 pts
153 spi
180 usb
189 usb_device
200 chrdevbase
226 drm
......[root@luckfox ]# rmmod chrdevbase.ko
[root@luckfox ]#
[root@luckfox ]#
[root@luckfox ]# dmesg
[ 2255.299762] chrdevbase_init
[ 2255.299798] register_chrdev
[ 2352.848928] unregister_chrdev
[ 2352.848966] chrdevbase_exit[root@luckfox ]# cat /proc/devices
Character devices:1 mem4 /dev/vc/04 tty4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx7 vcs10 misc13 input29 fb81 video4linux89 i2c90 mtd
116 alsa
128 ptm
136 pts
153 spi
180 usb
189 usb_device
226 drm
243 hidg
244 mpi
245 vcodec
246 mpp_service
247 rpmb
248 watchdog
249 iio
250 media
251 rtc
252 rk_dma_heap
253 ttyFIQ
254 gpiochip
......