1. bma250硬件原理
從全志A33的原理圖中,我們可以看到關(guān)于平板上使用的sensor傳感是使用的是bma250。BMA250是一種先進超小,三軸,低g加速度傳感器和數(shù)字接口,針對低功耗電子消費品的應用程序。這個BMA250允許測量加速度在3個互相垂直的軸,因此感官傾斜,運動,沖擊和振動在手機,手機,計算機外設(shè),人機界面,虛擬現(xiàn)實的特性和游戲控制器。我們可以看到這個芯片使用的i2c總線來操作從機設(shè)備,從機的地址為0x18。具體的設(shè)備信息請參看bma250.pdf文檔。
2. Android中bma250驅(qū)動的分析
我們接下來看bma250驅(qū)動,我們通過它的驅(qū)動文件,查看這個功能的實現(xiàn)。參考的文件如下:/home/linux/fspad-733/lichee/linux-3.4/drivers/hwmon/bma250.c
static int __init BMA250_init(void)
{
int ret = -1;
if (input_fetch_sysconfig_para(&(gsensor_info.input_type))) {
printk("%s: err.\n", __func__);
return -1;
} else
twi_id = gsensor_info.twi_id;
ret = i2c_add_driver(&bma250_driver);
return ret;
}
static void __exit BMA250_exit(void)
{
i2c_del_driver(&bma250_driver);
}
module_init(BMA250_init);
module_exit(BMA250_exit);
MODULE_LICENSE("GPL");
input_fetch_sysconfig_paraz這個函數(shù)是由來解析sys_config.fex這個配置文件的,你會發(fā)現(xiàn)全志很多配置信息沒有在平臺代碼中填寫,而是自己實現(xiàn)了配置文件。這個配置文件存放的路徑為fspad-733/lichee$ vi ./tools/pack/out/sys_config.fex。它獲取的時候是根據(jù)主鍵值和子鍵值來獲取的。
[gsensor_para]
gsensor_used = 1
gsensor_twi_id = 1
gsensor_twi_addr = 0x18
;gsensor_int1 = port:PB06<4><1><default><default>
[gsensor_list_para]
bma250 = 1
從這個配置文件中我們可以看到,這里包含從機的地址,i2c的sda和scl的端口地址。bma250=1,表示此傳感器是可以使用的。gsensor_twi_id = 1表示的是使用的i2c-1這個總線控制器。
當設(shè)備信息通過i2c總線匹配成功之后會執(zhí)行probe函數(shù),我們可以看到這里有
.class = I2C_CLASS_HWMON,
.detect = gsensor_detect,
.address_list = normal_i2c,
I2c總線也可以通過下面的方式匹配成功,重要的就是type,address這兩個成員,這種匹配方式前面已經(jīng)分析過了,這里就不在贅述了。當匹配成功之后會執(zhí)行probe函數(shù)。
.probe = bma250_probe,
1.定義結(jié)構(gòu)體
struct bma250_data {
struct i2c_client *bma250_client;
unsigned char mode;
struct input_dev *input;
struct bma250acc value;
struct delayed_work work;
struct work_struct irq_work;
unsigned char range_state;
unsigned char bandwidth_state;
};
2.為結(jié)構(gòu)體分配空間
data = kzalloc(sizeof(struct bma250_data), GFP_KERNEL);
3.結(jié)構(gòu)體成員的初始化
data->bma250_client = client; //將client成員賦值給data
bma250_set_bandwidth(client, BMA250_BW_SET);
設(shè)置帶寬bma250帶寬BMA250_BW_SET=4,通過驅(qū)動我們知道這里設(shè)置的是125hz,也就是說數(shù)據(jù)會4ms更新一次。
bma250_set_range(client, BMA250_RANGE_SET);
這里是設(shè)置加速度傳感器的量程范圍BMA250_RANGE_SET = 0
INIT_DELAYED_WORK(&data->work, bma250_work_func);
在data結(jié)構(gòu)體中存在一個delayed_work,這個結(jié)構(gòu)體中存在一個工作隊列和一個定時器,代碼展開情況如下,其中bma250_work_func是中斷低半部處理函數(shù)。
struct delayed_work {
struct work_struct work;
struct timer_list timer;
};
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
};
INIT_DELAYED_WORK(&data->work, bma250_work_func);
#define INIT_DELAYED_WORK(_work, _func) \
do { \
INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \
} while (0)
#define INIT_WORK(_work, _func) \
do { \
__INIT_WORK((_work), (_func), 0); \
} while (0)
#define init_timer(timer)\
init_timer_key((timer), NULL, NULL)
err = bma250_input_init(data); //初始化input
struct input_dev *dev;
dev = input_allocate_device();
input_set_capability(dev, EV_ABS, ABS_MISC);
input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0);
input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);
input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);
input_set_drvdata(dev, bma250);
err = input_register_device(dev);
err = sysfs_create_group(&data->input->dev.kobj,&bma250_attribute_group);
在驅(qū)動層創(chuàng)建了sysfs接口,HAL層通過這些sysfs接口,對Sensor進行操作,如使能、設(shè)置delay等
static struct attribute_group bma250_attribute_group = {
.attrs = bma250_attributes
};
static struct attribute *bma250_attributes[] = {
&dev_attr_range.attr,
&dev_attr_bandwidth.attr,
&dev_attr_mode.attr,
&dev_attr_value.attr,
&dev_attr_delay.attr,
&dev_attr_enable.attr,
NULL
};
static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_range_show, bma250_range_store);
static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_bandwidth_show, bma250_bandwidth_store);
static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_mode_show, bma250_mode_store);
static DEVICE_ATTR(value, S_IRUGO,
bma250_value_show, NULL);
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_delay_show, bma250_delay_store);
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_enable_show, bma250_enable_store);
這里一共會創(chuàng)建range,bandwidth,mode,value,delay,enable這些設(shè)備文件。range,bandwidth這兩個屬性文件我們就暫時不分析那么詳細了,前面我們已經(jīng)分析過了,這里主要是對量程范圍和帶框進行設(shè)置的,接下來還有一個mode的屬性文件,我們在平板的root@fspad-733:/sys/class/input/input4 #目錄下使用cat mode命令可以查看到這個設(shè)備文件的默認值為2
#define BMA250_MODE_NORMAL 0
#define BMA250_MODE_LOWPOWER 1
#define BMA250_MODE_SUSPEND 2
從它的定義處我們可以看出這是設(shè)置工作模型的,它有三種模式,正常,低電壓,掛起等這幾種工作模式。Value這個設(shè)備文件就是用來存放讀取到的當前的加速度計的當前的值的。我們使用cat命令查看。
root@fspad-733:/sys/class/input/input4 # cat value
4 12 -268
上面的數(shù)字對應的就是讀取到的x,y,z軸的數(shù)據(jù)。
Delay的設(shè)備文件就是用來設(shè)置當前的延時時間的,enable是用來設(shè)置當前bma250是否處在工作狀態(tài)。接下來我們需要重點分析value,delay,enable這三個設(shè)備文件對應的show和store方法。
2.1enable 設(shè)備文件分析
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_enable_show, bma250_enable_store);
通過前面我們所學的sysfs文件系統(tǒng)的知識我們知道,DEVICE_ATTR的后兩個參數(shù)分別為show和store方法。即對應的是bma250_enable_show和bma250_enable_store。
bma250_enable_show
struct bma250_data *bma250 = i2c_get_clientdata(client);
return sprintf(buf, "%d\n", atomic_read(&bma250->enable));
從上述的代碼我們可以清晰的知道,這里的show方法其實就是打印bma250結(jié)構(gòu)體中的enable的原子變量的數(shù)據(jù),這里只可能是0或1。
bma250_enable_store
error = strict_strtoul(buf, 10, &data); //將字符串轉(zhuǎn)化為整形數(shù)據(jù)
bma250_set_enable(dev,data);
if(pre_enable ==0){
bma250_set_mode(bma250->bma250_client,BMA250_MODE_NORMAL); schedule_delayed_work(&bma250->work,
msecs_to_jiffies(atomic_read(&bma250->delay)));
atomic_set(&bma250->enable, 1);
}
上面函數(shù)的功能是設(shè)置bma250的工作模式為正常模式,接著會使用schedule_delayed_work來調(diào)度中斷下半部,但是這里和我們之前使用的schedule_work函數(shù)有所區(qū)別,區(qū)別在于這里會延時一段時間在執(zhí)行調(diào)度函數(shù)。這里的延時時間在bma250結(jié)構(gòu)體的delay變量中保存著。這個delay的值猜想應該是在delay這個設(shè)備文件中獲取的。接著將atomic的enable設(shè)置為1。接下來我們看中斷低半部函數(shù)。
bma250_work_func
static void bma250_work_func(struct work_struct *work)
{
struct bma250_data *bma250 = container_of((struct delayed_work *)work,
struct bma250_data, work);
static struct bma250acc acc;
unsigned long delay = msecs_to_jiffies(atomic_read(&bma250->delay));
bma250_read_accel_xyz(bma250->bma250_client, &acc); //通過i2c去取數(shù)據(jù)
input_report_abs(bma250->input, ABS_X, acc.x); //上報x軸的數(shù)據(jù)
input_report_abs(bma250->input, ABS_Y, acc.y); //上報y軸的數(shù)據(jù)
input_report_abs(bma250->input, ABS_Z, acc.z); //上報z軸的數(shù)據(jù)
input_sync(bma250->input); //發(fā)送同步信號
bma250->value = acc; //將bma250中的value值更新
schedule_delayed_work(&bma250->work, delay); //延時調(diào)度本函數(shù)
}
上述的函數(shù)寫的很精髓,通過在中斷低半部使用schedule_delayed_work來調(diào)度中斷低半部,這樣就形成了循環(huán)從驅(qū)動中讀取數(shù)據(jù)。本次調(diào)度之間都有一個延時。去報驅(qū)動已經(jīng)將數(shù)據(jù)更新。接下來我們看下這個延時是怎么設(shè)置進來的。
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
bma250_delay_show, bma250_delay_store);
從前面的分析我們知道,工作隊列在調(diào)度時有一個延時,那么這個延時的時間怎么設(shè)置?它不可能是一個固定的值,它應該也為用戶提供了操作接口,在我們的這個文件中就是通過delay這個設(shè)備文件的方式。這個文件同樣對應連個方法,分別是show和store。
bma250_delay_show
return sprintf(buf, "%d\n", atomic_read(&bma250->delay));
這個函數(shù)十分的簡單,就是向buf換中區(qū)中寫入bma250結(jié)構(gòu)體的delay的值。通過測試。
root@fspad-733:/sys/class/input/input4 # cat delay
66
這里我們可以看到它是66毫秒。接下來分析store方法。
bma250_delay_store
error = strict_strtoul(buf, 10, &data);
if (data > BMA250_MAX_DELAY) //#define BMA250_MAX_DELAY 200
data = BMA250_MAX_DELAY; //限制延時的大值為200ms
atomic_set(&bma250->delay, (unsigned int) data);
將用戶寫的延時值設(shè)置進去。在驅(qū)動初始化的時候,我們可以看到這里并不是66而是200,那么它在什么時候進行初始化的那?很顯然應該是硬件抽象層調(diào)用的。這個暫時不用理會。
static DEVICE_ATTR(value, S_IRUGO,bma250_value_show, NULL);
bma250_value_show
return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y,acc_value.z);
這里很顯然就是將工作隊列中更新的值給打印出來。至此整個驅(qū)動我們就分析完成了。
3. bma250驅(qū)動的加載過程
3.1sys_config.fex文件的解析過程
在講解bma250驅(qū)動加載之前,我們需要在來講解一些知識。我們知道在bma250驅(qū)動的入口函數(shù)中input_fetch_sysconfig_para(&(gsensor_info.input_type),有這樣一句話,它的作用是解析sys_config.fex文件中的配置信息。
input_fetch_sysconfig_para(&(gsensor_info.input_type)
static struct sensor_config_info gsensor_info = {
.input_type = GSENSOR_TYPE,
};
struct sensor_config_info{
enum input_sensor_type input_type; //gsensor類型 1
int sensor_used; //設(shè)備是否可使用
__u32 twi_id;
u32 int_number;
struct gpio_config irq_gpio;
char* ldo;
struct device *dev;
struct pinctrl *pinctrl;
};
ret = (*fetch_sysconfig_para[*input_type])(input_type);
這里定義的是函數(shù)指針數(shù)組,上面?zhèn)鬟f過來的*input_type = 1,其中input_type又是
sensor_config_info結(jié)構(gòu)體的首地址
static int (* const fetch_sysconfig_para[])(enum input_sensor_type *input_type) = {
ctp_fetch_sysconfig_para,
gsensor_fetch_sysconfig_para,
gyr_fetch_sysconfig_para,
e_compass_fetch_sysconfig_para,
ls_fetch_sysconfig_para,
ir_fetch_sysconfig_para,
ths_fetch_sysconfig_para,
motor_fetch_sysconfig_para,
bat_fetch_sysconfig_para
};
所以接下來應該調(diào)用gsensor_fetch_sysconfig_para函數(shù),并將結(jié)構(gòu)體的首地址當參數(shù)傳遞過去。
static int gsensor_fetch_sysconfig_para(enum input_sensor_type *gsensor_type)
{
struct sensor_config_info *data =
container_of(gsensor_type,struct sensor_config_info, input_type);
//獲取sensor_config_info結(jié)構(gòu)體
type = script_get_item("gsensor_para", "gsensor_used", &val);
data->sensor_used = val.val;
if (1 == data->sensor_used) {
//如果sensor可使用就解析設(shè)備的數(shù)據(jù)
type = script_get_item("gsensor_para", "gsensor_twi_id", &val);
}
data->twi_id = val.val;
}
; G sensor configuration
; gs_twi_id --- TWI ID for controlling Gsensor (0: TWI0, 1: TWI1, 2: TWI2)
[gsensor_para]
gsensor_used = 1
gsensor_twi_id = 1
gsensor_twi_addr = 0x18
;gsensor_int1 = port:PB06<4><1><default><default>
script_get_item函數(shù)根據(jù)主鍵值和子鍵值進行獲取,具體的解析過程看如下目錄的文件即可。fspad-733/lichee/linux-3.4/arch/arm/mach-sunxi/sys_config.c 這整個過程的作用很明顯就是去讀sys_config.fex文件,然后決定當前bma250驅(qū)動是否能正常執(zhí)行。
3.2自動檢測函數(shù)的執(zhí)行過程
在如下目錄中fspad-733/lichee/linux-3.4/drivers/input/ 有sw-device.c的文件,這個文件的功能是自動檢測i2c設(shè)備,如果檢測到有i2c設(shè)備可以使用,則將可用的設(shè)備寫入device.info文件中。接下來我們分析一下這個文件。
從驅(qū)動入口函數(shù)開始看起
static struct device sw_device_detect = {
.init_name = "sw_device",
.release = sw_device_release,
};
static int __init sw_device_init(void)
{
sw_device_detect.groups = dev_attr_groups; //創(chuàng)建兩個屬性文件
err = device_register(&sw_device_detect); //設(shè)備文件的注冊過程
}
static void __exit sw_device_exit(void)
{
printk(" sw device driver exit!\n");
device_unregister(&sw_device_detect);
}
static DEVICE_ATTR(gsensor, S_IRUGO|S_IWUSR|S_IWGRP, sw_device_gsensor_show, sw_device_gsensor_store);
static DEVICE_ATTR(ctp, S_IRUGO|S_IWUSR|S_IWGRP, sw_device_ctp_show, sw_device_ctp_store);
在入口和出口函數(shù)中,我們可以看到設(shè)備文件的創(chuàng)建,上述
創(chuàng)建的gsensor和ctp(觸摸屏)這兩個屬性文件,但是他們的store
方法都沒有實現(xiàn),只實現(xiàn)了show方法,顯示的是設(shè)備名字和i2c
的從機地址。
root@fspad-733:/sys/devices/sw_device # cat gsensor
device name:bma250
device addr:0x19
在這個文件中我們還看到有uevent函數(shù)的實現(xiàn),這個函數(shù)在什么時候會執(zhí)行那?
當使用insmod sw-device.ko時這個event函數(shù)就會被回調(diào)。接下來我們重點分析
回調(diào)函數(shù)的執(zhí)行過程
static void sw_devices_events(struct work_struct *work)
{
int ret = -1;
int device_number = 0;
get_power_para(&c_power);
sw_devices_set_power(&c_power);
if(ctp_mask != 1) {
device_number = (sizeof(gsensors)) / (sizeof(gsensors[0]));
ret = sw_register_device_detect(gsensors, &g_name, device_number);
if(ret < 0)
printk("gsensor detect fail!\n");
}
...
}
在這個函數(shù)中調(diào)用很多次sw_register_device_detect函數(shù),這里我們就依gsensor來分析。
首先看一下它的參數(shù)gsensor是結(jié)構(gòu)體數(shù)組(如下),g_name是一個結(jié)構(gòu)體首地址(成員是不是很熟悉),
device_number是gsensor數(shù)組成員的個數(shù)。
static struct sw_device_info gsensors[] = {
{ "lsm9ds0_acc_mag", 0, {0x1e, 0x1d }, 0x0f, {0x49 }, 0},
{ "bma250", 0, {0x18, 0x19, 0x08, 0x38}, 0x00, {0x02,0x03,0xf9,0xf8}, 0},
{ "stk831x", 0, {0x3d, 0x22 }, 0x00, {0x00 }, 1},
{ "mma8452", 0, {0x1c, 0x1d }, 0x0d, {0x2A}, 0},
{ "mma7660", 0, {0x4c }, 0x00, {0x00 }, 0},
...
};
static struct para_name g_name = {
"gsensor_para",
"gsensor_used",
"gsensor_list_para",
"gsensor_det_used",
"gsensor_twi_id",
GSENSOR_DEVICE_KEY_NAME,
};
sw_register_device_detect(gsensors, &g_name, device_number);
struct sw_device *sw; //定義sw_device結(jié)構(gòu)體
sw = kzalloc(sizeof(*sw), GFP_KERNEL); //結(jié)構(gòu)體初始化
sw->temp_client = client; //地址賦值
sw->info = info;
sw->name = name;
sw->support_number = number;
sw->total_raw = DEFAULT_TOTAL_ROW;
#define NOTE_INFO1 ";Behind the equals sign said detected equipment
corresponding to the name of the driver\n"
#define NOTE_INFO2 ";Note: don't change the file format!\n"
#define GSENSOR_DEVICE_KEY_NAME "gsensor_module_name"
#define CTP_DEVICE_KEY_NAME "ctp_module_name"
#define LSENSOR_DEVICE_KEY_NAME "light sensor_module_name"
#define GYR_SENSOR_DEVICE_KEY_NAME "gyr sensor_module_name"
strcpy(sw->write_info[0].str_info, NOTE_INFO1);
strcpy(sw->write_info[1].str_info, NOTE_INFO2);
sprintf(sw->write_info[2].str_info, "%s=\"\"\n", GSENSOR_DEVICE_KEY_NAME);
sprintf(sw->write_info[3].str_info, "%s=\"\"\n", CTP_DEVICE_KEY_NAME);
sprintf(sw->write_info[4].str_info, "%s=\"\"\n", LSENSOR_DEVICE_KEY_NAME);
sprintf(sw->write_info[5].str_info, "%s=\"\"\n", GYR_SENSOR_DEVICE_KEY_NAME);
sprintf(sw->write_info[6].str_info, "%s=\"\"\n", COMPASS_SENSOR_DEVICE_KEY_NAME);
將字符串的信息寫入緩沖區(qū)中,接著開始調(diào)用sw_device_detect_start函數(shù)。
sw_device_detect_start(sw);
/*step1: Get sysconfig.fex profile information*/
sw_sysconfig_get_para(sw)
/*step 2:Read the device.info file information ,get device name!*/
sw_get_write_info(tmp, sw)
/*step 3: The i2c address detection equipment, find the device used at present.*/
sw_i2c_test(sw);
sw_device_response_test(sw, now_number);
adap = i2c_get_adapter(sw->twi_id); //獲取adapter
ret = i2c_test(sw->temp_client);
ret = i2c_write_bytes(client, test_data, 1); //Test i2c.
向當前的i2c設(shè)備中,寫入一個字節(jié),檢測當前的i2c設(shè)備是否可使用
sw_chip_id_detect(sw, now_number)
檢測從設(shè)備中讀取到的id信息是否和表中的相匹配。
/*step 4:Update the device.info file information*/
sw_set_write_info(sw);
如果前面的設(shè)備都匹配成功了,這里就會將匹配成功的信息寫入到device.info中。在平板運行的時候我們可以找到它在sensors_cache/device.info目錄下,我們可以看到它的信息如下:
;Behind the equals sign said detected equipment corresponding to
the name of the driver
;Note: don't change the file format!
gsensor_module_name="bma250"
ctp_module_name="gslX680new"
light sensor_module_name=""
gyr sensor_module_name=""
compass sensor_module_name=""
3.3device.info中的驅(qū)動加載過程
從上述的文件中,我們可以看到檢測成功的有bma250驅(qū)動,還有g(shù)slX680new驅(qū)動,這兩個驅(qū)動在編譯的時候我們可以通過make menuconfig ARCH=arm看到
Device Drivers --->
<*> Hardware Monitoring support --->
<M> BMA250 acceleration sensor support
它被編譯成了模塊側(cè)形式,那么這個驅(qū)動什么時候被加載的那?很多同學第一時間會想到應該是在fspad-733/androidL/device/softwinner/fspad-733/ init.sun8i.rc文件中,但是你在這個文件中怎么搜索都搜索不到。難道驅(qū)動會自動加載?這種情況是不可能的;叵肭懊娴倪^程這些驅(qū)動是在device.info中寫的,如果說想加載這個驅(qū)動的話,首先一定會打開sensors_cache/device.info這個文件,基于這種思想,你可以使用grep “sensors_cache/device.info” * -nR。終你會找到fspad-733/androidL/device/softwinner/common/hardware/libhardware/libsensors/aw_sensors/insmodDevice.cpp這個文件。
struct sensors_module_t HAL_MODULE_INFO_SYM
methods: &sensors_module_methods,
open: open_sensors
insmodDevice();
get_cfg()
fp = fopen(I2C_DEVICE_CONFIG_PATH,"rb")
#define I2C_DEVICE_CONFIG_PATH ("sensors_cache/device.info")
fgets(buf, LINE_LENGTH , fp)
insmod_modules(buf)
module_name = get_module_name(buf);//獲取到的驅(qū)動為bma250
#define INSMOD_PATH ("system/vendor/modules/")
char ko[] = ".ko";
sprintf(insmod_name,"%s%s%s",INSMOD_PATH,module_name,ko);
終insmod_name = system/vendor/modules/bma250.ko
insmod(insmod_name, "")
至此,驅(qū)動就能夠成功加載了。
4.sensor的硬件抽象層的代碼分析
sensor的hal層涉及到的結(jié)構(gòu)體
對任意一個sensor設(shè)備都會有一個sensor_t結(jié)構(gòu)體,其定義如下:
struct sensor_t {
constchar* name; //傳感器名字
constchar* vendor;
int version; //版本
int handle; //傳感器的handle句柄
int type; //傳感器類型
float maxRange; //大范圍
float resolution; //解析度
float power; //消耗能源
int32_t minDelay; //事件間隔小時間
void* reserved[8]; //保留字段,必須為0
};
每個傳感器的數(shù)據(jù)由sensors_event_t結(jié)構(gòu)體表示,定義如下:
typedef structsensors_event_t {
int32_t version;
int32_tsensor; //標識符
int32_ttype; //傳感器類型
int32_t reserved0;
int64_ttimestamp; //時間戳
union {
float data[16];
sensors_vec_t acceleration; //加速度
sensors_vec_t magnetic; //磁矢量
sensors_vec_t orientation; //方向
sensors_vec_t gyro; //陀螺儀
float temperature; //溫度
float distance; //距離
float light; //光照
float pressure; //壓力
float relative_humidity; //相對濕度
};
uint32_t reserved1[4];
}sensors_event_t;
其中,sensor為傳感器的標志符,而不同的傳感器則采用union方式來表示,sensors_vec_t結(jié)構(gòu)體用來表示不同傳感器的數(shù)據(jù), sensors_vec_t 定義如下:
typedef struct {
union {
float v[3];
struct {
float x;
float y;
float z;
};
struct {
float azimuth;
float pitch;
float roll;
};
};
int8_t status;
uint8_t reserved[3];
} sensors_vec_t;
Sensor設(shè)備結(jié)構(gòu)體sensors_poll_device_t,對標準硬件設(shè)備hw_device_t結(jié)構(gòu)體的擴展,主要完成讀取底層數(shù)據(jù),并將數(shù)據(jù)存儲在struct sensors_poll_device_t結(jié)構(gòu)體中,poll函數(shù)用來獲取底層數(shù)據(jù),調(diào)用時將被阻塞定義如下:
struct sensors_poll_device_t {
struct hw_device_t common;
//Activate/deactivate one sensor
int(*activate)(struct sensors_poll_device_t *dev,
int handle, int enabled);
//Set the delay between sensor events in nanoseconds for a givensensor.
int(*setDelay)(struct sensors_poll_device_t *dev,
int handle, int64_t ns);
//獲取數(shù)據(jù)
int(*poll)(struct sensors_poll_device_t *dev,
sensors_event_t* data, int count);
};
Gsensor的硬件抽象層的代碼在fspad-733/androidL/device/softwinner/common/hardware/libhardware/libsensors/aw_sensors目錄下,對應的文件是sensors.cpp和sensors.h。硬件抽象層代碼在編寫的時候首先要定義hw_module_t的結(jié)構(gòu)體,但是在這個文件中我們沒有發(fā)現(xiàn)這個結(jié)構(gòu)體取而代之的是sensors_module_t結(jié)構(gòu)體,它把hw_module_t放在首元素的位置。
//#define SENSORS_HARDWARE_MODULE_ID "sensors"
struct sensors_module_t HAL_MODULE_INFO_SYM = {
common: {
id: SENSORS_HARDWARE_MODULE_ID,
methods: &sensors_module_methods,
},
get_sensors_list: sensors__get_sensors_list,
};
struct sensors_module_t {
struct hw_module_t common;
int (*get_sensors_list)(struct sensors_module_t* module,
struct sensor_t const** list);
};
上述對sensors_module_t中不必要的成員進程了剔除,可能有些同學看著很別扭,賦值不是使用=嗎?為什么這里使用的是:。這是c++里面的規(guī)則。效果是相同的。接下來我們分析sensor中的操作方法。
static struct hw_module_methods_t sensors_module_methods = {
open: open_sensors
};
static int open_sensors(const struct hw_module_t* module, const char* id,
struct hw_device_t** device)
{
int status = -EINVAL;
insmodDevice(); //安裝bma250驅(qū)動
property_set("sys.sensors", "1");//設(shè)置屬性
sensorsDetect(); //sensor的自檢測
sensors_poll_context_t *dev = new sensors_poll_context_t(); //定義結(jié)構(gòu)體
memset(&dev->device, 0, sizeof(sensors_poll_device_t));
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = poll__close;
dev->device.activate = poll__activate;
dev->device.setDelay = poll__setDelay;
dev->device.poll = poll__poll; //填充操作方法
*device = &dev->device.common; //將結(jié)構(gòu)體返回給上層
return 0;
}
驅(qū)動的安裝過程前面我們已經(jīng)分析過了,終會調(diào)用insmod函數(shù)。屬性的設(shè)置暫時不去理會,我們來分析一下驅(qū)動的自檢測過程。
sensorsDetect();
char *dirname =(char *) "/sys/class/input";
dir = opendir(dirname); //打開dirname獲取這個目錄的流指針
de = readdir(dir) //讀取目錄下的文件
strncmp(de->d_name, "input", strlen("input")) //匹配和input相同的項
sprintf(classPath, "%s/%s", dirname, de->d_name);
classPath = /sys/class/input/input(0-n)
snprintf(buf, sizeof(buf), "%s/name", classPath);
buf = /sys/class/input/input0/name
fd = open(buf, O_RDONLY); //打開上述找到的屬性文件
read(fd, buf, sizeof(buf) //讀取文件的內(nèi)容
axp22-supplyer input0
headset input1
sunxi-ths input2
sunxi-keyboard input3
bma250 input4
gslX680 input5
searchDevice(buf, classPath);
otherDeviceDetect(buf);
/*static struct o_device otherDevice[] = {
{
0, "sw-",
}, {
0, "axp",
},
};*/
if(!otherDevice[number0].isFind){
if (!strncmp(buf, otherDevice[number0].name,strlen(otherDevice[number0].name))) {
otherDevice[number0].isFind = 1;
re_value = 1;
}
從這里我們可以看到它匹配的是axp芯片,當然下面還有匹配其他的,這里我們暫時不關(guān)心,
我們只看bma250的匹配過程。
/*struct sensor_extend_t gsensorList[] = {
{
{
"bma250", LSG_BMA250,
}, {
"Bosch 3-axis Accelerometer",
"Bosch",
1, 0,
SENSOR_TYPE_ACCELEROMETER,
4.0f*9.81f,
(4.0f*9.81f)/1024.0f,
0.2f, 0,
0,0,SENSOR_STRING_TYPE_ACCELEROMETER,
0,0,SENSOR_FLAG_WAKE_UP,
{ },
},
}
}*/
ret = getDevice(gsensorList, &gsensorInfo, buf, classPath,ARRAY_SIZE(gsensorList));
if (!strncmp(buf, list[ret].sensors.name, strlen(buf))) {
info->priData = list[ret].sensors.lsg;
setSensorData(sNumber, &list[ret].sList);
sSensorList[number].name = sensorList->name;
sSensorList[number].vendor = sensorList->vendor;
strncpy(info->sensorName, buf,strlen(buf));
strncpy(info->classPath, classPath, strlen(classPath));
}
將匹配到的信息進行賦值,將sensor_t的信息保存在sSensorList的數(shù)組中,將其他的信息
保存在gsensorInfo結(jié)構(gòu)體中。將classPath也保存進去。
struct sensors_poll_device_t {
struct hw_device_t common;
int (*activate)(struct sensors_poll_device_t *dev,int sensor_handle, int enabled);
int (*setDelay)(struct sensors_poll_device_t *dev,int sensor_handle, int64_t sampling_period_ns);
int (*poll)(struct sensors_poll_device_t *dev,sensors_event_t* data, int count);
};
struct sensors_poll_context_t {
struct sensors_poll_device_t device; // must be first
int activate(int handle, int enabled);
int setDelay(int handle, int64_t ns);
int pollEvents(sensors_event_t* data, int count);
private:
int accel;
static const size_t wake = 10;
static const char WAKE_MESSAGE = 'W';
struct pollfd mPollFds[11];
int mWritePipeFd;
SensorBase* mSensors[10];
int handleToDriver(int handle) const {
switch (handle) {
case ID_A:
return accel;
}
return -EINVAL;
}
};
sensors_poll_context_t *dev = new sensors_poll_context_t();
sensors_poll_context_t::sensors_poll_context_t()
:gyro(-1),
orn(-1),
press(-1)
{
if((seStatus[ID_A].isUsed == true) && (seStatus[ID_A].isFound == true)) {
first = first + 1;
accel = first;
mSensors[first] = new AccelSensor();
//創(chuàng)建加速度計對象,保存在mSensors[0]中,這里會打開/dev/input/eventX設(shè)備節(jié)點
mPollFds[first].fd = mSensors[accel]->getFd();
mPollFds[first].events = POLLIN;
mPollFds[first].revents = 0;
}
...
int wakeFds[2];
int result = pipe(wakeFds);
ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
mWritePipeFd = wakeFds[1];
mPollFds[wake].fd = wakeFds[0];
mPollFds[wake].events = POLLIN;
mPollFds[wake].revents = 0;
}
Hal層的代碼我們暫時分析到這里,接下來我們分析jni代碼的調(diào)用過程。
5.hal代碼的調(diào)用
fspad-733/androidL/frameworks/native/services/sensorservice/SensorDevice.cpp
SensorDevice::SensorDevice()
: mSensorDevice(0),
mSensorModule(0)
{
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, //”sensors”
(hw_module_t const**)&mSensorModule);
fspad-733/androidL/frameworks/native/services/sensorservice/SensorDevice.cpp
SensorDevice::SensorDevice()
: mSensorDevice(0),
mSensorModule(0)
{
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, //”sensors”
(hw_module_t const**)&mSensorModule);
//通過SENSORS_HARDWARE_MODULE_ID來獲取sensors_module_t的結(jié)構(gòu)體
if (mSensorModule) //如果獲取的結(jié)構(gòu)體不為空,則調(diào)用sensors_open_1函數(shù)
err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
module->methods->open(module,SENSORS_HARDWARE_POLL, (struct hw_device_t**)device);
這個open的過程就是前面我們所分析的。
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
get_sensors_list: sensors__get_sensors_list,
static int sensors__get_sensors_list(struct sensors_module_t* module,struct sensor_t const** list)
*list = sSensorList;
返回sensorsDetect函數(shù)填充的sSensorList數(shù)組的首地址。
mSensorDevice->activate((struct sensors_poll_device_t *)(mSensorDevice),list[i].handle, 0);
dev->device.activate = poll__activate;
sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
return ctx->activate(handle, enabled);
int sensors_poll_context_t::activate(int handle, int enabled) {
int index = handleToDriver(handle);
int handleToDriver(int handle) const {
switch (handle) {
case ID_A:
return accel; //這個handle=0,代碼取出的是加速度計的變量
err |= mSensors[index]->setEnable(handle, enabled);
int AccelSensor::setEnable(int32_t handle, int en)
if(mUser > 0)
err = enable_sensor();
else //從上面?zhèn)鬟^來的數(shù)據(jù)我們知道這里執(zhí)行else語句
err = disable_sensor();
int AccelSensor::disable_sensor() {
return writeEnable(0);
int bytes = sprintf(buf, "%d", isEnable);
err = set_sysfs_input_attr(gsensorInfo.classPath,"enable",buf,bytes);
snprintf(path, sizeof(path), "%s/%s", class_path, attr);
path = /sys/class/input/input4/enable
fd = open(path, O_RDWR);
write(fd, value, len)
//操作sys下的設(shè)備文件,向enable的設(shè)備文件中寫入0,暫時關(guān)閉bma250功能
}
這是我們從下層向上層的分析的思路,至此我們已經(jīng)分析完成,但是它的poll函數(shù)如何被調(diào)用,數(shù)據(jù)如何獲取我們還不知道,接下來我們從上層向下層來分析。
Java熱點新聞
主講人:Java講師Hidi
主講人:Java講師Hidi>
主講人:Java講師Hidi