一,前言
所謂學習,那麼就和單純完成任務是不同的,我的學習也是有目標的,那麼從linux驅動開發的角度來說,若只是配置下就能用了,這樣有點知其然而不知其所以然,所以我的目標就是先會用,然後學習框架及源碼,便於將來遇到問題後調試定位和代碼優化。另外,最主要的就是學習linux中面向對象的抽象設計思路。所以做完了SG90的PWM後,那麼就要分析PWM源碼了。並且發現了看源碼有助於我在寫驅動的時候對函數的理解及應用。
二,PWM源碼框架
PWM框架算是比較簡單的。我畫了個圖備忘下。
三,PWM源碼分析
每個pwm-芯片.c都會調用pwmchip_add,比如ti的am335芯片,配置了pwm及使能設備樹後。
1.ehrpwm_pwm_probe->pwmchip_add(pwm-tiehrpwm.c)添加PWM驅動。
2.pc->chip.ops = &ehrpwm_pwm_ops;將註冊的芯片pwm操作掛到chip ops中。
3.pwmchip_add->pwmchip_sysfs_export(core.c)添加到pwm radix樹中,以供將來使用時搜索請求設備。
4.pwmchip_sysfs_export->device_create(sysfs.c)進行設備文件創建。
pwm文件夾中core.c是中間代理,自制驅動開始使用pwm是通過調用pwm_request(request a PWM device)開始的,我覺得它就類似於gpio_request、gpio_free的作用。pwm子系統和i2c不同的原因在於i2c它還有一個總線的概念,所以多出來了adapter和algorithm進行i2c和SMBus的抽象。
pwm_request->pwm_device_request(core.c)
pwm->chip->ops->request會跳入具體註冊的pwm中(在pwmchip_add中已經掛載綁定了關係)。
看到如下源碼,我發現SG90驅動在open文件的時候也不需要加鎖,因爲request調用的時候會檢查此pwm資源是否空閒,否則返回-EBUSY。我只要將-EBUSY返回給APP即可。
static int pwm_device_request(struct pwm_device *pwm, const char *label)
{
int err;
if (test_bit(PWMF_REQUESTED, &pwm->flags))
return -EBUSY;
if (!try_module_get(pwm->chip->ops->owner))
return -ENODEV;
if (pwm->chip->ops->request) {
err = pwm->chip->ops->request(pwm->chip, pwm);
if (err) {
module_put(pwm->chip->ops->owner);
return err;
}
}
set_bit(PWMF_REQUESTED, &pwm->flags);
pwm->label = label;
return 0;
}
四,遇到的問題
我對sysfs,debugfs,config文件系統不熟悉只是死板的使用,所以第一天我搭建pwm硬件環境的時候,沒有寫任何代碼,直接設置pwm文件即可操作pwm,原理是什麼呢?通過看源碼也找到答案了。在pwm的core.c中,initail call會調用pwm_debugfs_init->debugfs_create_file
通過debugfs_create_file就可以在debugfs中建立一個文件結點,就像字符設備驅動那樣,只需要對這個文件結點進行open就可以進行read、write、ioctl,等等操作。
static const struct file_operations pwm_debugfs_ops = {
.owner = THIS_MODULE,
.open = pwm_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};