linux misc混雜裝置驅動 .
阿新 • • 發佈:2019-02-07
一. misc結構體
struct miscdevice {
int minor; //次裝置號
const char *name; //裝置名
const struct file_operations *fops; //操作函式集
struct list_head list; //連結串列頭
struct device *parent; //父裝置裝置檔案
struct device *this_device; //裝置檔案
const char *nodename; //
mode_t mode; //
};
二. 裝置號
misc裝置的主裝置號為10
#define MISC_MAJOR 10
三. misc裝置系統的初始化 misc_init
static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); //建立目錄"/sys/class/misc" err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //註冊為字元裝置,捆綁操作函式集 goto fail_printk; misc_class->devnode = misc_devnode; return 0; fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; }
再看一下register_chrdev
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
這裡直接根據主裝置號建立256個裝置,256=2^8,所以它是把所有的雜項裝置都給註冊成字元裝置了
misc_fops作為這所有misc裝置捆綁的操作函式集
static const struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, .llseek = noop_llseek, };
在misc_open中,也就是我們開啟misc裝置的時候,misc_open方法會為我們捆綁自定義的操作函式集
static int misc_open(struct inode * inode, struct file * file)
{
int minor = iminor(inode); //根據裝置節點獲取次裝置號
struct miscdevice *c;
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) { //遍歷misc_list檢視次裝置是否註冊(misc_list元素在設備註冊時新增)
if (c->minor == minor) {
new_fops = fops_get(c->fops); //獲取自定義的操作函式集
break;
}
}
if (!new_fops) { //若找不到則再找一次,還不行error
mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops)
goto fail;
}
err = 0;
old_fops = file->f_op; //獲取指向舊的裝置操作函式集(misc_fops)指標
file->f_op = new_fops; //檔案操作函式集指標指向新的操作函式集
if (file->f_op->open) { //若存在open方法
file->private_data = c;
err=file->f_op->open(inode,file); //則呼叫其自定義的open方法
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
}
fops_put(old_fops); //釋放舊的函式集指標
fail:
mutex_unlock(&misc_mtx);
return err;
}
四. misc設備註冊 misc_register
int misc_register(struct miscdevice * misc)
{
struct miscdevice *c;
dev_t dev;
int err = 0;
INIT_LIST_HEAD(&misc->list); //初始化連結串列頭
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) { //遍歷misc_list
if (c->minor == misc->minor) { //檢視裝置號是否被佔用
mutex_unlock(&misc_mtx);
return -EBUSY;
}
}
if (misc->minor == MISC_DYNAMIC_MINOR) { //判斷是否指定要動態分配次裝置號
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); //查詢可用次裝置號
if (i >= DYNAMIC_MINORS) {
mutex_unlock(&misc_mtx);
return -EBUSY;
}
misc->minor = DYNAMIC_MINORS - i - 1; //分配次裝置號
set_bit(i, misc_minors); //設定佔用標誌位
}
dev = MKDEV(MISC_MAJOR, misc->minor); //根據主次裝置號獲取裝置號
misc->this_device = device_create(misc_class, misc->parent, dev,misc, "%s", misc->name); //新增裝置檔案"/dev/xxx"
if (IS_ERR(misc->this_device)) {
int i = DYNAMIC_MINORS - misc->minor - 1;
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors);
err = PTR_ERR(misc->this_device);
goto out;
}
/*
* Add it to the front, so that later devices can "override"
* earlier defaults
*/
list_add(&misc->list, &misc_list); //將裝置連結串列頭新增到misc_list中
out:
mutex_unlock(&misc_mtx);
return err;
}
五. misc設備註銷 misc_deregister
int misc_deregister(struct miscdevice *misc)
{
int i = DYNAMIC_MINORS - misc->minor - 1; //通過次裝置號計算出位標誌
if (WARN_ON(list_empty(&misc->list)))
return -EINVAL;
mutex_lock(&misc_mtx);
list_del(&misc->list); //從misc_list刪除裝置連結串列頭
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); //刪除裝置節點
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors); //清除位標誌
mutex_unlock(&misc_mtx);
return 0;
}
六. misc簡單例項
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
static int test_open(struct inode * inode, struct file * filp)
{
return 0;
}
static const struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
};
static struct miscdevice misc_dev={
.minor=MISC_DYNAMIC_MINOR,
.name="misc_test",
.fops=&test_fops
};
static int __init test_init(void)
{
return misc_register(&misc_dev);
}
static void __exit test_exit(void)
{
misc_deregister(&misc_dev);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
七. 檢視misc資訊的方法
載入模組後
lsmod |grep test
test 829 0
ls -l /dev/misc_test
crw-rw---- 1 root root 10, 54 2012-12-18 10:28 /dev/misc_test
ls -l /sys/class/misc/ |grep misc_test
lrwxrwxrwx 1 root root 0 2012-12-18 10:33 misc_test -> ../../devices/virtual/misc/misc_test
cat /proc/misc |grep misc_test
54 misc_test