當前位置: 首頁 > 安卓培訓 > Android開發 > Android-sensor驅動和硬件抽象層
          Android-sensor驅動和硬件抽象層 時間:2018-08-16     來源:未知

          1. bma250硬件原理

          從全志A33的原理圖中,我們可以看到關于平板上使用的sensor傳感是使用的是bma250。BMA250是一種先進超小,三軸,低g加速度傳感器和數字接口,針對低功耗電子消費品的應用程序。這個BMA250允許測量加速度在3個互相垂直的軸,因此感官傾斜,運動,沖擊和振動在手機,手機,計算機外設,人機界面,虛擬現實的特性和游戲控制器。我們可以看到這個芯片使用的i2c總線來操作從機設備,從機的地址為0x18。具體的設備信息請參看bma250.pdf文檔。

          2. Android中bma250驅動的分析

          我們接下來看bma250驅動,我們通過它的驅動文件,查看這個功能的實現。參考的文件如下:/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這個函數是由來解析sys_config.fex這個配置文件的,你會發現全志很多配置信息沒有在平臺代碼中填寫,而是自己實現了配置文件。這個配置文件存放的路徑為fspad-733/lichee$ vi ./tools/pack/out/sys_config.fex。它獲取的時候是根據主鍵值和子鍵值來獲取的。

          [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這個總線控制器。

          當設備信息通過i2c總線匹配成功之后會執行probe函數,我們可以看到這里有

          .class = I2C_CLASS_HWMON,

          .detect     = gsensor_detect,

          .address_list   = normal_i2c,

          I2c總線也可以通過下面的方式匹配成功,重要的就是type,address這兩個成員,這種匹配方式前面已經分析過了,這里就不在贅述了。當匹配成功之后會執行probe函數。

          .probe      = bma250_probe,

          1.定義結構體

          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.為結構體分配空間

            data = kzalloc(sizeof(struct bma250_data), GFP_KERNEL);

          3.結構體成員的初始化

          data->bma250_client = client;                  //將client成員賦值給data

          bma250_set_bandwidth(client, BMA250_BW_SET);

          設置帶寬bma250帶寬BMA250_BW_SET=4,通過驅動我們知道這里設置的是125hz,也就是說數據會4ms更新一次。

          bma250_set_range(client, BMA250_RANGE_SET);

          這里是設置加速度傳感器的量程范圍BMA250_RANGE_SET = 0

          INIT_DELAYED_WORK(&data->work, bma250_work_func);

          在data結構體中存在一個delayed_work,這個結構體中存在一個工作隊列和一個定時器,代碼展開情況如下,其中bma250_work_func是中斷低半部處理函數。

          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);   

          在驅動層創建了sysfs接口,HAL層通過這些sysfs接口,對Sensor進行操作,如使能、設置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);

          這里一共會創建range,bandwidth,mode,value,delay,enable這些設備文件。range,bandwidth這兩個屬性文件我們就暫時不分析那么詳細了,前面我們已經分析過了,這里主要是對量程范圍和帶框進行設置的,接下來還有一個mode的屬性文件,我們在平板的[email protected]:/sys/class/input/input4 #目錄下使用cat mode命令可以查看到這個設備文件的默認值為2

          #define BMA250_MODE_NORMAL     0

          #define BMA250_MODE_LOWPOWER   1

          #define BMA250_MODE_SUSPEND     2

          從它的定義處我們可以看出這是設置工作模型的,它有三種模式,正常,低電壓,掛起等這幾種工作模式。Value這個設備文件就是用來存放讀取到的當前的加速度計的當前的值的。我們使用cat命令查看。

          [email protected]:/sys/class/input/input4 # cat value

          4  12  -268

          上面的數字對應的就是讀取到的x,y,z軸的數據。

          Delay的設備文件就是用來設置當前的延時時間的,enable是用來設置當前bma250是否處在工作狀態。接下來我們需要重點分析value,delay,enable這三個設備文件對應的show和store方法。

          2.1enable 設備文件分析

          static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,

                  bma250_enable_show, bma250_enable_store);

          通過前面我們所學的sysfs文件系統的知識我們知道,DEVICE_ATTR的后兩個參數分別為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結構體中的enable的原子變量的數據,這里只可能是0或1。

          bma250_enable_store

          error = strict_strtoul(buf, 10, &data);  //將字符串轉化為整形數據

          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);

          }

          上面函數的功能是設置bma250的工作模式為正常模式,接著會使用schedule_delayed_work來調度中斷下半部,但是這里和我們之前使用的schedule_work函數有所區別,區別在于這里會延時一段時間在執行調度函數。這里的延時時間在bma250結構體的delay變量中保存著。這個delay的值猜想應該是在delay這個設備文件中獲取的。接著將atomic的enable設置為1。接下來我們看中斷低半部函數。

          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去取數據

              input_report_abs(bma250->input, ABS_X, acc.x);  //上報x軸的數據

              input_report_abs(bma250->input, ABS_Y, acc.y);  //上報y軸的數據

              input_report_abs(bma250->input, ABS_Z, acc.z);  //上報z軸的數據

              input_sync(bma250->input);                  //發送同步信號

              bma250->value = acc;                     //將bma250中的value值更新

              schedule_delayed_work(&bma250->work, delay); //延時調度本函數

          }

          上述的函數寫的很精髓,通過在中斷低半部使用schedule_delayed_work來調度中斷低半部,這樣就形成了循環從驅動中讀取數據。本次調度之間都有一個延時。去報驅動已經將數據更新。接下來我們看下這個延時是怎么設置進來的。

          static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,

                   bma250_delay_show, bma250_delay_store);

          從前面的分析我們知道,工作隊列在調度時有一個延時,那么這個延時的時間怎么設置?它不可能是一個固定的值,它應該也為用戶提供了操作接口,在我們的這個文件中就是通過delay這個設備文件的方式。這個文件同樣對應連個方法,分別是show和store。

          bma250_delay_show

          return sprintf(buf, "%d\n", atomic_read(&bma250->delay));

          這個函數十分的簡單,就是向buf換中區中寫入bma250結構體的delay的值。通過測試。

          [email protected]:/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);

          將用戶寫的延時值設置進去。在驅動初始化的時候,我們可以看到這里并不是66而是200,那么它在什么時候進行初始化的那?很顯然應該是硬件抽象層調用的。這個暫時不用理會。

          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);

          這里很顯然就是將工作隊列中更新的值給打印出來。至此整個驅動我們就分析完成了。

          3. bma250驅動的加載過程

          3.1sys_config.fex文件的解析過程

          在講解bma250驅動加載之前,我們需要在來講解一些知識。我們知道在bma250驅動的入口函數中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;                      //設備是否可使用

          __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);

          這里定義的是函數指針數組,上面傳遞過來的*input_type = 1,其中input_type又是

          sensor_config_info結構體的首地址

          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

          };

          所以接下來應該調用gsensor_fetch_sysconfig_para函數,并將結構體的首地址當參數傳遞過去。

          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結構體

          type = script_get_item("gsensor_para", "gsensor_used", &val);

          data->sensor_used = val.val;    

          if (1 == data->sensor_used) {      

          //如果sensor可使用就解析設備的數據

          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函數根據主鍵值和子鍵值進行獲取,具體的解析過程看如下目錄的文件即可。fspad-733/lichee/linux-3.4/arch/arm/mach-sunxi/sys_config.c  這整個過程的作用很明顯就是去讀sys_config.fex文件,然后決定當前bma250驅動是否能正常執行。

          3.2自動檢測函數的執行過程

          在如下目錄中fspad-733/lichee/linux-3.4/drivers/input/ 有sw-device.c的文件,這個文件的功能是自動檢測i2c設備,如果檢測到有i2c設備可以使用,則將可用的設備寫入device.info文件中。接下來我們分析一下這個文件。

          從驅動入口函數開始看起

          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;   //創建兩個屬性文件                                                                           

              err = device_register(&sw_device_detect);    //設備文件的注冊過程

          }

          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);

          在入口和出口函數中,我們可以看到設備文件的創建,上述

          創建的gsensor和ctp(觸摸屏)這兩個屬性文件,但是他們的store

          方法都沒有實現,只實現了show方法,顯示的是設備名字和i2c

          的從機地址。

          [email protected]:/sys/devices/sw_device # cat gsensor

          device name:bma250

          device addr:0x19

          在這個文件中我們還看到有uevent函數的實現,這個函數在什么時候會執行那?

          當使用insmod sw-device.ko時這個event函數就會被回調。接下來我們重點分析

          回調函數的執行過程

          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");

          }

          ...

          }

          在這個函數中調用很多次sw_register_device_detect函數,這里我們就依gsensor來分析。

          首先看一下它的參數gsensor是結構體數組(如下),g_name是一個結構體首地址(成員是不是很熟悉),

          device_number是gsensor數組成員的個數。

          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結構體

           sw = kzalloc(sizeof(*sw), GFP_KERNEL);  //結構體初始化

           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);

          將字符串的信息寫入緩沖區中,接著開始調用sw_device_detect_start函數。

          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設備中,寫入一個字節,檢測當前的i2c設備是否可使用

          sw_chip_id_detect(sw, now_number)

          檢測從設備中讀取到的id信息是否和表中的相匹配。

          /*step 4:Update the device.info file information*/

          sw_set_write_info(sw);

          如果前面的設備都匹配成功了,這里就會將匹配成功的信息寫入到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中的驅動加載過程

          從上述的文件中,我們可以看到檢測成功的有bma250驅動,還有gslX680new驅動,這兩個驅動在編譯的時候我們可以通過make menuconfig ARCH=arm看到

          Device Drivers  --->

          <*> Hardware Monitoring support  --->  

          <M>   BMA250 acceleration sensor support

          它被編譯成了模塊側形式,那么這個驅動什么時候被加載的那?很多同學第一時間會想到應該是在fspad-733/androidL/device/softwinner/fspad-733/ init.sun8i.rc文件中,但是你在這個文件中怎么搜索都搜索不到。難道驅動會自動加載?這種情況是不可能的。回想前面的過程這些驅動是在device.info中寫的,如果說想加載這個驅動的話,首先一定會打開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);//獲取到的驅動為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, "")

          至此,驅動就能夠成功加載了。

          4.sensor的硬件抽象層的代碼分析

          sensor的hal層涉及到的結構體

          對任意一個sensor設備都會有一個sensor_t結構體,其定義如下:

          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

          };

          每個傳感器的數據由sensors_event_t結構體表示,定義如下:

          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結構體用來表示不同傳感器的數據, 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設備結構體sensors_poll_device_t,對標準硬件設備hw_device_t結構體的擴展,主要完成讀取底層數據,并將數據存儲在struct sensors_poll_device_t結構體中,poll函數用來獲取底層數據,調用時將被阻塞定義如下:

          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);

             //獲取數據

             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的結構體,但是在這個文件中我們沒有發現這個結構體取而代之的是sensors_module_t結構體,它把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++里面的規則。效果是相同的。接下來我們分析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驅動

          property_set("sys.sensors", "1");//設置屬性

          sensorsDetect();  //sensor的自檢測

          sensors_poll_context_t *dev = new sensors_poll_context_t(); //定義結構體

          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;  //將結構體返回給上層

          return 0;

          }

          驅動的安裝過程前面我們已經分析過了,終會調用insmod函數。屬性的設置暫時不去理會,我們來分析一下驅動的自檢測過程。

          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)   //讀取文件的內容

          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芯片,當然下面還有匹配其他的,這里我們暫時不關心,

          我們只看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的數組中,將其他的信息

          保存在gsensorInfo結構體中。將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();   

          //創建加速度計對象,保存在mSensors[0]中,這里會打開/dev/input/eventX設備節點

                  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代碼的調用過程。

          5.hal代碼的調用 

          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的結構體

          if (mSensorModule)  //如果獲取的結構體不為空,則調用sensors_open_1函數

          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函數填充的sSensorList數組的首地址。

          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   //從上面傳過來的數據我們知道這里執行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下的設備文件,向enable的設備文件中寫入0,暫時關閉bma250功能

          }

          這是我們從下層向上層的分析的思路,至此我們已經分析完成,但是它的poll函數如何被調用,數據如何獲取我們還不知道,接下來我們從上層向下層來分析。

          前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2018 北京華清遠見科技發展有限公司

          Android培訓

          版權所有 ,京ICP備16055225號,京公海網安備11010802025203號
          内蒙古十一选五软件