標籤:
前言
最近在拜讀羅昇陽的《Android系統原始碼情景分析》一書,相信有許多搞android系統的人會去看看本書,那麼針對於第二章的硬體抽象層,聯絡一下實際的工作,有必要將自己學習的東西做一個總結分析。當然這部分將依據老羅的書的思路一一揭開硬體抽象層的面紗。
檔案系統介面
一般kernel層會給使用者層暴露相關的介面供使用者空間去使用。大致上可以被分為三類。
- proc檔案系統介面
- 傳統裝置檔案系統介面
- devfs檔案系統介面
其中proc檔案系統介面與傳統裝置檔案系統介面一脈相承,它們和起來才能做一個較為完善的檔案系統介面。
proc檔案系統介面與傳統裝置檔案系統介面
它是由傳統裝置檔案操作方法與傳統裝置檔案操作方法表fops組成。老羅一書中用了freg.c這個檔案來做解釋的,但實際真正在使用過程中還需大家自己去體悟。
在這裡將通過我自己寫的charger介面作為例子進行分析。
看到static int smbchg_probe(struct spmi_device *spmi)函數,會讓其直接調用create函數來建立一個檔案系統介面。
create_batt_voltage_proc_file();
然後看這個函數的定義
void static create_batt_voltage_proc_file(void){ batt_voltage_proc_file = proc_create(batt_voltage_PROC_FILE, 0644, NULL, &batt_voltage_fops); if (batt_voltage_proc_file) { printk("[Proc]%s sucessed!\n", __FUNCTION__); } else{ printk("[Proc]%s failed!\n", __FUNCTION__); }}
可以看到,其主要工作是將fops掛載上去。按圖索驥。
#define batt_voltage_PROC_FILE "batt_voltage_now"static const struct file_operations batt_voltage_fops = { .owner = THIS_MODULE, .open = batt_voltage_proc_open, .read = seq_read, .release = single_release,};
fops已經出現了,其實他會掛在載/porc/batt_voltage_now,這都得歸功於函數proc_create(batt_voltage_PROC_FILE, 0644, NULL, &batt_voltage_fops);當然在這裡沒有看到
下面看open。
static int batt_voltage_proc_open(struct inode *inode, struct file *file){ return single_open(file, batt_voltage_proc_read, NULL);}
其主要就是為了回調single_open(file, batt_voltage_proc_read, NULL);中的batt_voltage_proc_read。
static int batt_voltage_proc_read(struct seq_file *buf, void *v){ int ret = -1; struct power_supply *psy; union power_supply_propval val; int voltage_now=0; psy = get_psy_battery(); ret = psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); if (!ret) { voltage_now = val.intval / 1000; seq_printf(buf, "%d\n", voltage_now); } else{ printk("%s: can‘t get voltage_now, ret = %d!\n", __FUNCTION__, ret); voltage_now = ret; } return 0;}
這樣就可以看到這個函數的主要功能就是將電壓值除以1000後回傳給介面。
小結一下:其核心思想就是為了將fops掛載上去。
devfs檔案系統介面
我們以hall_sensor為例。
static DEVICE_ATTR(status, 0664, show_action_status, store_action_status);static struct attribute *hall_sensor_attrs[] = { &dev_attr_status.attr, NULL};static struct attribute_group hall_sensor_group = { .name = "hall_sensor", .attrs = hall_sensor_attrs};
這段code已經清晰顯示需要架設的東西了。通過DEVICE_ATTR去建立devfs檔案系統。並提供相關的動作節點show_action_status, store_action_status。
/*=========================== *|| sysfs DEVICE_ATTR part || *=========================== * */static ssize_t show_action_status(struct device *dev,struct device_attribute *attr, char *buf){ if(!hall_sensor_dev) return sprintf(buf, "Hall sensor does not exist!\n"); return sprintf(buf, "%d\n",hall_sensor_dev->status);}static ssize_t store_action_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ int request; unsigned long flags; //if(!hall_sensor_dev) // return sprintf(buf, "Hall sensor does not exist!\n"); sscanf(buf, "%du", &request); spin_lock_irqsave(&hall_sensor_dev->mHallSensorLock, flags); if (!request) hall_sensor_dev->status = 0; else hall_sensor_dev->status = 1; spin_unlock_irqrestore(&hall_sensor_dev->mHallSensorLock, flags); log("[ATTR] status rewite value = %d\n",!hall_sensor_dev->status); return count;}
在此我不便分析其具體功能。但其思想便是做掛載的動作。
後續
當然在這裡我僅僅是將kernel部分的節點方式做了簡單介紹,抽空將hardware,framwork層如何工作的補上。
參考部落格
proc_create的使用方法
proc_create和create_proc_entry的區別
漫談android系統(6)硬體抽象層kernel分析