主要資料結構:
struct cdev ;
//通過i節點可以判斷裝置是字元裝置還是塊裝置,並得到裝置號,得到裝置號找到kobject,在通過kobject找到cdev
//怎麼通過裝置號找到kobject的,可以通過下面這個資料結構和相關的函式實現
struct kobj_map *probes[255];
struct mutex *lock;
};可以將這個資料結構,分成兩部分
struct probe ;
struct kobj_map ;
先來分析這個結構的用法,具體看和它相關的幾個函式:
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
struct module *module, kobj_probe_t *probe,
int (*lock)(dev_t, void *), void *data) //為裝置號位dev,範圍為range的裝置申請probe結構,並加入domain中進行管理
mutex_lock(domain->lock); //要操作domain了,互斥操作
for (i = 0, p -= n; i < n; i++, p++, index++)
mutex_unlock(domain->lock); //操作完了
return 0;
}//疑問???
//每個domain定義了255個probe的指標指向乙個鍊錶,每個鍊錶代表主裝置號相同的裝置,那麼這個列表上的range加起來可能大於255個次裝置號??,
//繼續往下看,看完後就明白了,
void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) //這個函式完成和上面函式相反的過程}}
mutex_unlock(domain->lock);
kfree(found); //釋放資源
}//關鍵函式,在domain中查詢裝置號dev的kobject
struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
mutex_unlock(domain->lock);
kobj = probe(dev, index, data); //通過註冊的函式得到kobj
/* currently ->owner protects _only_ ->probe() itself. */
module_put(owner);
if (kobj)
return kobj;//返回kobj
goto retry;
}mutex_unlock(domain->lock);//解鎖
return null;
}//初始化,並返回
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
base->dev = 1;
base->range = ~0;
base->get = base_probe;
for (i = 0; i < 255; i++) //初始化所有的煉表頭
p->probes[i] = base;
p->lock = lock;
return p;
}接著看,字元裝置是怎麼使用kobj_map管理kobject的:
chrdev_init()呼叫
--》cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
//cdev_map是個全域性的變數,賦值管理所有的字元裝置的kobject
i cdev_add(struct cdev *p, dev_t dev, unsigned count)
//上面用的的兩個函式
static struct kobject *exact_match(dev_t dev, int *part, void *data)
static int exact_lock(dev_t dev, void *data)
//通過上面的資料結構能找到裝置號對應的cdev了,但這還不夠,我沒還需要對驅動進行管理,比如申請裝置號??所以有了下面乙個資料結構
static struct char_device_struct *chrdevs[255]; //定義了255個主裝置,每個主裝置號用到乙個該指標
//申請裝置號
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
int minorct, const char *name)
if (i == 0)
major = i;
ret = major;
}cd->major = major;
cd->baseminor = baseminor;
cd->minorct = minorct;
strncpy(cd->name,name, 64); //
i = major_to_index(major);
/* new driver overlaps from the left. */
if (new_max >= old_min && new_max <= old_max)
/* new driver overlaps from the right. */
if (new_min <= old_max && new_min >= old_min)
}cd->next = *cp;//將申請的裝置號加入到找的char_device_struct的前面,這樣保證了從小到大的排序
*cp = cd;
mutex_unlock(&chrdevs_lock);
return cd;
out:
mutex_unlock(&chrdevs_lock);
kfree(cd);
return err_ptr(ret);
}static struct char_device_struct *
__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
mutex_unlock(&chrdevs_lock);
return cd;
}int register_chrdev_region(dev_t from, unsigned count, const char *name) //申請裝置號
return 0;
fail:
to = n;
for (n = from; n < to; n = next)
return ptr_err(cd);
}int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)//動態的分配裝置號
int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops) //註冊字元裝置,256次裝置
void unregister_chrdev(unsigned int major, const char *name)
//完成上面相反的工作
//這個函式描述了怎麼講字元裝置和設相關的操作連線到一起在看他之前我們來看
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
static int chrdev_open(struct inode *inode, struct file *filp)
else if (!cdev_get(p))
ret = -enxio;
} else if (!cdev_get(p))
ret = -enxio;
spin_unlock(&cdev_lock);
cdev_put(new);
if (ret)
return ret;
ret = -enxio;
filp->f_op = fops_get(p->ops);
if (!filp->f_op)
goto out_cdev_put;
if (filp->f_op->open)
return 0;
out_cdev_put:
cdev_put(p);
return ret;
}這樣整個流程字元裝置的整體架構就清楚了。關於kobject、kset、class、bus、driver、device需要慢慢梳理。
總結:字元裝置用法
首先申請字元裝置號 有兩個函式
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)//動態的分配裝置號
int register_chrdev_region(dev_t from, unsigned count, const char *name) //指定裝置號
然後呼叫
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
還用很多複雜的函式如 cdev_alloc等等。。。。
這是字元裝置的核心部分,其實對於驅動開發更多的還是在kops操作函式的實現上。
我對字元裝置驅動的理解
實驗要求 編寫簡單的字元裝置驅動模組,能夠支援建立和刪除節點,節點進行讀寫操作時分別列印 you are reading 和 you are writing 思想整理 1.本實驗需要我們編寫乙個驅動程式,如mymodule.c 2.該驅動程式經編譯後生成.ko檔案,使用makefile檔案生成mym...
對序列裝置的理解
大學畢業之前一直都沒有接觸到嵌入式,所以對這個概念的理解也是很糊,網際網路上也比較難找到通俗易懂的定義。下面我來說說我自己的理解 這也是uart存在的目的,在序列通訊和並行通訊間作為乙個中間者轉換。因為計算機內部使用並行資料,不可能直接把並行資料傳到序列裝置中。過程是這樣的 cpu先把準備寫入序列裝...
字元裝置入門理解
基本字元裝置驅動模型 1.字元裝置驅動程式設計步驟 1 定義乙個字元裝置結構體struct cdev 用來描述某個字元裝置 2 初始化字元裝置結構體,struct file operations檔案操作集合 cdev init 3 申請裝置號 id 4 註冊字元裝置cdev add 5 建立裝置檔案...