高通耳机检测分析

Bp部分主要是注册中断事件,检测到中断后上报key_code给ap,通过rpc机制传递给ap端。

Ap部分驱动层注册rpc客户端,对事件进行处理,uevent上报相应的事件类型,应用层开机启动wiredaccessoryobserver服务,侦听到耳机事件后发送setdeviceconnectionstate到策略层,选择输出设备,驱动层根据设备切换到对应的音频通路,音频通路再通过acdb文件调用bp对应的通路的codec和snd,完成了通路的切换。

 

/*===========================bp部分=====================================*/

Hs_gpio.c

 

耳机检测分析,插入耳机检测通过中断机制判断的,

1.系统启动时mp侧先调用hsi_gpio_init函数中 hsi_gpio_process_isr_event(0, (timer_cb_data_type)gpio_id) 处理gpio_id中断事件。

 

hsi_gpio_process_isr_event函数中设置中断 

/* Set interrupt to fire when GPIO flips again */

Gpio状态翻转时设置中断激活

  hs_tramp_gpio_register_isr((uint32)gpio_data->gpio_num, trigger,

                      hsi_gpio_detect_isr, (uint32)gpio_id);

 

2.gpio正常情况下不会发生变化,插入耳机后将会因电平变化有中断产生,因此开机后从his_gpio_detect_isr开始执行

void hsi_gpio_detect_isr(uint32 gpio_id)

{

  boolean is_intrpt_enabled;

  hsi_gpio_data_type *gpio_data;

  gpio_data = (hsi_gpio_data + gpio_id);

 

  /* Read the GPIO. If it is low set the interrupt to be level trigerred for

   * high level. If it is high, set the interrupt for level trigerred for low

   * level.

   * Active value for the GPIO is determined from configuration data

   */

  if (gpio_id < HS_GPIO_LAST)

  {

    is_intrpt_enabled = hs_tramp_gpio_is_interrupt_enabled(gpio_data->gpio_num);

 

    if (TRUE == is_intrpt_enabled)

    {

      hs_tramp_gpio_deregister_isr((uint32)gpio_data->gpio_num,

                            hsi_gpio_detect_isr);

    }

 

    if(INVALID_GPIO_DEBOUNCE_PERIOD != gpio_data->timer_delay  &&

       TRUE == gpio_data->timer_initialzed)

    {

    HS_MSG_HIGH("if xx%s: hs_report_event %d", __FUNCTION__, gpio_id, 0);

      /* Start the timer to debounce GPIO level change on GPIO */

/*设置定时器,消除GPIO电平变化的抖动*/

      timer_reg( &(gpio_data->gpio_timer),

                 (timer_t2_cb_type)hsi_gpio_process_isr_event,

                 (timer_cb_data_type)gpio_id, gpio_data->timer_delay, 0

               );

}

 

 

 

关于1调用情况分析结构体:

hs_poll_src_type hsi_gpio_handle =

{

  hsi_gpio_init,

  hsi_gpio_poll,

  hsi_gpio_close,

};

 

hs_poll_table_type hsi_poll_list[HS_EVNT_LAST] =

{

  {NULL,                HS_GPIO_EXT_PWR, 0},    /* External Power */

  {NULL,                        HS_GPIO_HSD,     0},    /* Headset        */

  {NULL,                HS_GPIO_HSTD,    0},    /* Headset Type   */

  {NULL,                HS_GPIO_NONE,    0},    /* Headset Switch */

  {NULL,                HS_GPIO_NONE,    0},    /* Keypad         */

  {&hsi_pwr_key_handle, HS_GPIO_NONE,    0},    /* PWR/END        */

  {NULL,                HS_GPIO_FLIP,    0},    /* Flip state     */

  {NULL,                HS_GPIO_CHARGER, 0},    /* Charger        */

  {NULL,                HS_GPIO_NONE,    0},    /* Runtime env    */

  {NULL,                HS_GPIO_NONE,    0},    /* Remote evts    */

  {NULL,                HS_GPIO_NONE,    0},    /* Diag events    */

  {&hsi_gpio_handle,    HS_GPIO_NONE,     0},    /* Accessory evts */

  {NULL,                HS_GPIO_NONE,    0},    /* headphone evts */

  {NULL,                HS_GPIO_NONE,    0},    /* mic detect evts*/

  {&hsi_acc_type_drv_handle,           HS_GPIO_ACCESSORY,    0},    /* acc type detect evts*/

 

上述结构体表明

hsi_poll_list[HS_EVNT_ACCESSORY_DETECT].handle触发hsi_gpio_handle,检测插入中断事件

hsi_poll_list[HS_EVNT_ACC_TYPE_DETECT].handle触发hsi_acc_type_drv_handle,区分耳机

 

 

 

void hs_task  -

static void hs_init( void )  -

                   hsi_init_plugins();

 

hsi_init_plugins()函数中

  for (i = (hs_event_type)0; i < HS_EVNT_LAST; ++i)

  {

    HSI_EVNT_DRIVER(i) = (hs_poll_src_type *)NULL;

    HSI_EVNT_POLL_STATUS(i) = HS_POLL_SRC_INACTIVE;

    HSI_EVNT_LAST_STATE(i) = HS_SRC_STATE_UNKWN;

 

    if (NULL != hsi_poll_list[i].handle)

    {

      if (NULL != hsi_poll_list[i].handle->init)

      {

        result = (hsi_poll_list[i].handle->init)(&hsi_cfg_data, (void *)NULL);

      }

 

      if ((HS_SUCCESS == result) && (NULL != hsi_poll_list[i].handle->poll))

      {

        HSI_EVNT_DRIVER(i) = hsi_poll_list[i].handle;

        /* Check if the poll source uses interrupts. If it does set it up as

         * ACTIVE_INTERRUPT so that it does not get polled.

         */

         HS_MSG_HIGH("%s: i=%d if(0==%d)", __FUNCTION__, i, hsi_poll_list[i].poll_interval);

        if (0 == hsi_poll_list[i].poll_interval)

        {

          HSI_EVNT_POLL_STATUS(i) = HS_POLL_SRC_ACTIVE_INTERRUPT;

        }

        else

        {

          HSI_EVNT_POLL_STATUS(i) = HS_POLL_SRC_ACTIVE;

          ++hsi_poll_plugins_num;

        }

      }

    }

    else

    {

      HSI_EVNT_DRIVER(i) = (hs_poll_src_type *)NULL;

      HSI_EVNT_POLL_STATUS(i) = HS_POLL_SRC_INACTIVE;

    }

 

    hsi_poll_data[i].gpio = hsi_poll_list[i].gpio_id;

 

    hsi_set_poll_data_skip_cnt(i);

  }

 

根据  @file hs_bsp_v.c设置结构体情况设置hsi_poll_list[i].handle,如果poll_interval0的时候,就将poll状态设为中断,i11result = (hsi_poll_list[i].handle->init)(&hsi_cfg_data, (void *)NULL);会调用hsi_gpio_init函数

  

hs_return_type hsi_gpio_init(const hs_config_data_type *cfg, void *handle)

 

/*===========================ap部分=====================================*/

 

耳机驱动文件

1.Rpc_server_handset.c

 

probe文件看看该文件的作用,定义了全局的变量

 

struct msm_handset {

         struct input_dev *ipdev;

         struct switch_dev sdev;开关设备

         struct msm_handset_platform_data *hs_pdata;

         bool mic_on, hs_on;

};

static struct msm_rpc_client *rpc_client;通过rpc机制获取bp事件

static struct msm_handset *hs;

 

1.1注册开关设备

         hs->sdev.name         = "h2w";

         hs->sdev.print_name = msm_headset_print_name;

 

         rc = switch_dev_register(&hs->sdev);

通过switch_dev_register就会生成目录:/sys/class/switch/h2w

及其下面的"/sys/class/switch/h2w/name";"/sys/class/switch/h2w/state";文件。对了,接口就是这两个文件

由驱动通过update_stateà switch_set_state将rpc获取的耳机名称和状态,写入namestate

应用程序对耳机进行名称和状态的判断就靠读出这两个文件得到。

 

1.2注册input设备,

 

ipdev = input_allocate_device();

input_set_drvdata(ipdev, hs);

hs->ipdev = ipdev;

if (pdev->dev.platform_data)

                   hs->hs_pdata = pdev->dev.platform_data;

         ipdev->id.vendor      = 0x0001;

         ipdev->id.product    = 1;

         ipdev->id.version      = 1;

 

         input_set_capability(ipdev, EV_KEY, KEY_MEDIA);

         input_set_capability(ipdev, EV_KEY, KEY_VOLUMEUP);

         input_set_capability(ipdev, EV_KEY, KEY_VOLUMEDOWN);

         input_set_capability(ipdev, EV_SW, SW_HEADPHONE_INSERT);

         input_set_capability(ipdev, EV_SW, SW_MICROPHONE_INSERT);

         input_set_capability(ipdev, EV_KEY, KEY_POWER);

         input_set_capability(ipdev, EV_KEY, KEY_END);

         set_bit(INPUT_PROP_NO_FAKE_RELEASE, ipdev->propbit);

 

         rc = input_register_device(ipdev);

1.3 初始化rpc客户端,接收bp上报的事件

         rc = hs_rpc_init();

 

à rc = msm_rpc_create_server(&hs_rpc_server);

à static struct msm_rpc_server hs_rpc_server = {

         .prog                  = HS_SERVER_PROG,

         .vers                   = HS_SERVER_VERS,

         .rpc_call   = handle_hs_rpc_call,

};

à             report_hs_key(args->key_code, args->key_parm);

 

1.4 report_hs_key函数上报key事件

 

//根据key_code是松开(0xff)还是其他确定hs_find_key()的参数是param还是code

         if (key_code == HS_REL_K)

                   key = hs_find_key(key_parm);

         else

                   key = hs_find_key(key_code);

 

static int hs_find_key(uint32_t hscode)

{

         int i, key;

//hscode保存在高8位,0保存在低24

         key = KEY(hscode, 0);

//循环查hs_key_map,这个数组最后一个元素定义为0

         for (i = 0; hs_key_map[i] != 0; i++) {

//8位为当前key值的,取出其相应的低24位返回函数

                   if ((hs_key_map[i] & 0xff000000) == key)

                            return hs_key_map[i] & 0x00ffffff;

         }

         return -1;

}

 

Input_report_key

Input_report_switch

根据上报key事件和开关事件进行不同处理

这里有无mic的事件做了区分,update时会将h2w/state更新,但是input时没有区分出来。

 

2,应用层获取耳机状态文件WiredAccessoryObserver.java

调用关系

onuevent

->updatestate

  ->update

    ->handlemessage

      ->setdevicesState

        ->setdevicestate

 

Audiomanager.java

publicvoidsetWiredDeviceConnectionState(int device,int state, String name)

 

Audioservice.java

setDeviceconnectionState对应audiopolicymanager.cpp中的函数(JNI机制)

调用HAL层中的设备可以实现驱动通路的切换。

 

下面对应用分析比较透彻,对上层UI通过发送消息通知变更外设图标

http://my.eoe.cn/cnhua5/archive/1252.html

你可能感兴趣的:(高通耳机检测分析)