MTK Headset 实现音乐按键功能

走在前面的人有饭吃,走在后面的人没饭吃,技术先人一步,你就是赢家,欢迎到未来新技术手机操作系统firefox os 5狐论坛网"www.5fox.cn"


mediatek/platform/mt6577/kernel/drivers/accdet/accdet.c



module_init(accdet_mod_init);
module_exit(accdet_mod_exit);
事件驱动在开机的时候就已经加载


static int accdet_probe(struct platform_device *dev)
{
 ............
//开启一个上报事件线程
 keyEvent_thread = kthread_run(sendKeyEvent, 0, "keyEvent_send");
     if (IS_ERR(keyEvent_thread))
{
        error = PTR_ERR(keyEvent_thread);
        ACCDET_DEBUG( " failed to create kernel thread: %d\n", error);
     }
.............
}




//ACCDET state machine switch
static inline void check_cable_type(void)
{
..............
   //检测按键状态变换
switch (multi_key)
{
case SHORT_UP:
ACCDET_DEBUG("[Accdet] Short press up (0x%x)\n", multi_key);
                                                if(call_status == 0)
                                                {
                                                        notify_sendKeyEvent(ACC_MEDIA_PREVIOUS);
                                                }
  else
  {
          notify_sendKeyEvent(ACC_VOLUMEUP);
  }
break;
case SHORT_MD:
ACCDET_DEBUG("[Accdet] Short press middle (0x%x)\n", multi_key);
                                                if(call_status == 0)
                                                        notify_sendKeyEvent(ACC_MEDIA_PLAYPAUSE);
                                                else
                                                        notify_sendKeyEvent(ACC_ANSWER_CALL);
break;
case SHORT_DW:
ACCDET_DEBUG("[Accdet] Short press down (0x%x)\n", multi_key);
                                                if(call_status == 0)
                                                {
                                                        notify_sendKeyEvent(ACC_MEDIA_NEXT);
                                                }
  else
  {
          notify_sendKeyEvent(ACC_VOLUMEDOWN);
  }
break;
case LONG_UP:
ACCDET_DEBUG("[Accdet] Long press up (0x%x)\n", multi_key);
break;
case LONG_MD:
ACCDET_DEBUG("[Accdet] Long press middle (0x%x)\n", multi_key);
                                                if(call_status == 0)
                                                        notify_sendKeyEvent(ACC_MEDIA_STOP);
                                                else
                                                        notify_sendKeyEvent(ACC_END_CALL);
break;
case LONG_DW:
ACCDET_DEBUG("[Accdet] Long press down (0x%x)\n", multi_key);
break;
default:
ACCDET_DEBUG("[Accdet] unkown key (0x%x)\n", multi_key);
break;
}
}
#else
             if(call_status != 0)
     {
                               if(is_long_press())
                            {
                                                ACCDET_DEBUG("[Accdet]send long press remote button event %d \n",ACC_END_CALL);
                                                notify_sendKeyEvent(ACC_END_CALL);
                                        } else {
                                                ACCDET_DEBUG("[Accdet]send short press remote button event %d\n",ACC_ANSWER_CALL);
                                                notify_sendKeyEvent(ACC_ANSWER_CALL);
                                        }
           }
#ifdef JRD_HEADSET_MUSIC_KEY
else {
            if(is_long_press())
            {
                        ACCDET_DEBUG("[Accdet]long press remote button to go to next song!\n");
                        notify_sendKeyEvent(ACC_MEDIA_NEXT);
                    } else {
                        ACCDET_DEBUG("[Accdet]short press remote button to pause/play music!\n");
                        notify_sendKeyEvent(ACC_MEDIA_PLAYPAUSE);
                    }
                }
#endif
#endifend  ifdef ACCDET_MULTI_KEY_FEATURE else
#else
           if(call_status != 0)
   {
if(is_long_press())
    {
        ACCDET_DEBUG("[Accdet]long press remote button to end call!\n");
   input_report_key(kpd_accdet_dev, KEY_ENDCALL, 1);
   input_report_key(kpd_accdet_dev, KEY_ENDCALL, 0);
                input_sync(kpd_accdet_dev);
      }
            else
     {
       ACCDET_DEBUG("[Accdet]short press remote button to accept call!\n");
   input_report_key(kpd_accdet_dev, KEY_CALL, 1);
   input_report_key(kpd_accdet_dev, KEY_CALL, 0);
                input_sync(kpd_accdet_dev);
     }
}
        #ifdef JRD_HEADSET_MUSIC_KEY
  else {
            if(is_long_press())
            {
                        ACCDET_DEBUG("[Accdet]long press remote button to go to next song!\n");
                        input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 1);
                        input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 0);
                        input_sync(kpd_accdet_dev);
                    } else {
                        ACCDET_DEBUG("[Accdet]short press remote button to pause/play music!\n");
                        input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 1);
                        input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 0);
                        input_sync(kpd_accdet_dev);
                    }
                }
#endif
#endif
}
            }
            else if(current_status == 1)
            {
                accdet_status = MIC_BIAS;
           cable_type = HEADSET_MIC;
                ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n");
            }
            else if(current_status == 3)
            {
                #ifdef ACCDET_MULTI_KEY_FEATURE
  ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n");
  #else
      accdet_status = PLUG_OUT;
          cable_type = NO_DEVICE;
  #ifdef ACCDET_EINT
      disable_accdet();
  #endif
      #endif
            }
            else
            {
               ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n");
            }
            break;


        case DOUBLE_CHECK:
            if(current_status == 0)
            {
                ///*MT6577 E1*: resolve the hardware issue:
                double_check_workaround();
            }
            else if(current_status == 2)
            {
                //ALPS00053818:when plug in iphone headset half, accdet detects tv-out plug in,
//and then plug in headset completely, finally plug out it and can't detect plug out
//Reason: tv signal(32mA) is abnormal by plug in tv cable in tv-out state.
//Solution:increase debounce2(tv debounce) to a long delay to prevent accdet
//stay in tv-out state again because of tv signal(32 mA) isn't stable.
OUTREG32(ACCDET_DEBOUNCE2, 0xffff);


       accdet_status = TV_OUT;
                cable_type = HEADSET_NO_MIC;


       OUTREG32(ACCDET_CTRL, ACCDET_DISABLE);
       enable_tv_allwhite_signal(false);
                enable_tv(true);


if(double_check_flag == 1)
{
     tv_headset_icon = true;
}


            }
            else if(current_status == 3)
            {
    ///*MT6577 E1*: resolve the hardware issue:
    //fast plug out headset after plug in with hook switch pressed,
                //accdet detect mic bias instead of plug_out state.
                double_check_workaround();
            }
            else
            {
                ACCDET_DEBUG("[Accdet]DOUBLE_CHECK can't change to this state!\n");
            }
            break;


        case HOOK_SWITCH:
            if(current_status == 0)
            {
                cable_type = HEADSET_NO_MIC;
       accdet_status = HOOK_SWITCH;
                ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n");
   }
            else if(current_status == 1)
            {
       accdet_status = MIC_BIAS;
       cable_type = HEADSET_MIC;


//ALPS00038030:reduce the time of remote button pressed during incoming call
                //solution: reduce hook switch debounce time to 0x400
                OUTREG32(ACCDET_DEBOUNCE0, button_press_debounce);
            }
            else if(current_status == 3)
            {
                    #ifdef ACCDET_MULTI_KEY_FEATURE
ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n");
#else
      accdet_status = PLUG_OUT;
      cable_type = NO_DEVICE;
  #ifdef ACCDET_EINT
      disable_accdet();
      #endif
      #endif
            }
            else
            {
                ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n");
            }
            break;


        case TV_OUT:
      OUTREG32(ACCDET_DEBOUNCE0, cust_headset_settings.debounce0);
   OUTREG32(ACCDET_DEBOUNCE3, cust_headset_settings.debounce3);
   //ALPS00053818: resume debounce2 when jump out from tv-out state.
   OUTREG32(ACCDET_DEBOUNCE2, tv_out_debounce);


            if(current_status == 0)
            {
OUTREG32(ACCDET_RSV_CON3, ACCDET_DEFVAL_SEL);
ACCDET_DEBUG("[Accdet]TV-out state: ACCDET_RSV_CON3=0x%x \n\r", INREG32(ACCDET_RSV_CON3));


                if(Is_TvoutEnabled())
             {
                 //*MT6573 E1&E2*:work around method for plug in headset  uncompletely with remote button pressed
                 //solution:when plug in headset completely, tv_out->hook_switch because of AB=00
                 accdet_status = HOOK_SWITCH;
cable_type = HEADSET_NO_MIC;
            ACCDET_DEBUG("[Accdet]headset plug in with remote button completely now!\n");
             }
else
{
                 //work around method
accdet_status = STAND_BY;
ACCDET_DEBUG("[Accdet]TV out is disabled with tv cable plug in!\n");
}


enable_tv(false);
                enable_tv_detect(false);


OUTREG32(ACCDET_RSV_CON3, 0);
           }
            else if(current_status == 3)
            {
                 #ifdef ACCDET_MULTI_KEY_FEATURE
   ACCDET_DEBUG("[Accdet]accdet do not send plug out event in TV out!\n");
   #else
    accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
                enable_tv(false);
        enable_tv_detect(false);
#ifdef ACCDET_EINT
   disable_accdet();//should  disable accdet here because enable_tv(false) will enalbe accdet
         #endif
   #endif
           }
  else if(current_status == 2)
  {
       //ALSP00092273
       OUTREG32(ACCDET_DEBOUNCE0, 0x4);
       OUTREG32(ACCDET_DEBOUNCE3, 0x4);


  }
            else
            {
                ACCDET_DEBUG("[Accdet]TV_OUT can't change to this state!\n");
            }
            break;


        case STAND_BY:
            if(current_status == 3)
            {
                 #ifdef ACCDET_MULTI_KEY_FEATURE
   ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n");
   #else
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
#ifdef ACCDET_EINT
   disable_accdet();
   #endif
   #endif
            }
            else
            {
                ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n");
            }
            break;


        default:
            ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n");
            break;


    }


...................


}
//触发事件上报线程,这样就在sendKeyEvent(int event)中上报底层事件到上层应用
static ssize_t notify_sendKeyEvent(int event)
{


    accdet_key_event = event;
    atomic_set(&send_event_flag, 1);
    wake_up(&send_event_wq);
    ACCDET_DEBUG( " accdet:notify_sendKeyEvent !\n");
    return 0;
}


static int sendKeyEvent(void *unuse)
{
    while(1)   //在这个线程里面添加按键所报的事件
    {
        ACCDET_DEBUG( " accdet:sendKeyEvent wait\n");
        //wait for signal
        wait_event_interruptible(send_event_wq, (atomic_read(&send_event_flag) != 0));


        wake_lock_timeout(&accdet_key_lock, 2*HZ);    //set the wake lock.
        ACCDET_DEBUG( " accdet:going to send event %d\n", accdet_key_event);
/*
        Workaround to avoid holding the call when pluging out.
        Added a customized value to in/decrease the delay time.
        The longer delay, the more time key event would take.
*/
#ifdef KEY_EVENT_ISSUE_DELAY
        if(KEY_EVENT_ISSUE_DELAY >= 0)
                msleep(KEY_EVENT_ISSUE_DELAY);
        else
        msleep(500);
#else
        msleep(500);
#endif
        if(PLUG_OUT !=accdet_status)
        {
            //send key event
            if(ACC_ANSWER_CALL == accdet_key_event)
            {
                ACCDET_DEBUG("[Accdet] answer call!\n");
                input_report_key(kpd_accdet_dev, KEY_CALL, 1);
                input_report_key(kpd_accdet_dev, KEY_CALL, 0);
                input_sync(kpd_accdet_dev);
            }
            if(ACC_END_CALL == accdet_key_event)
            {
                ACCDET_DEBUG("[Accdet] end call!\n");
                input_report_key(kpd_accdet_dev, KEY_ENDCALL, 1);
                input_report_key(kpd_accdet_dev, KEY_ENDCALL, 0);
                input_sync(kpd_accdet_dev);
            }
#ifdef ACCDET_MULTI_KEY_FEATURE
            if(ACC_MEDIA_PLAYPAUSE == accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] PLAY_PAUSE !\n");
                                input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 1);
                                input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 0);
                                input_sync(kpd_accdet_dev);
            }
            if(ACC_MEDIA_STOP == accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] STOP !\n");
                                input_report_key(kpd_accdet_dev, KEY_STOPCD, 1);
                                input_report_key(kpd_accdet_dev, KEY_STOPCD, 0);
                                input_sync(kpd_accdet_dev);
            }
            if(ACC_MEDIA_NEXT == accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] NEXT ..\n");
                                //input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 1);
                                //input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 0);
                               // input_sync(kpd_accdet_dev);
            }
            if(ACC_MEDIA_PREVIOUS == accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] PREVIOUS..\n");
                               // input_report_key(kpd_accdet_dev, KEY_PREVIOUSSONG, 1);
                                //input_report_key(kpd_accdet_dev, KEY_PREVIOUSSONG, 0);
                               // input_sync(kpd_accdet_dev);
            }
     if(ACC_VOLUMEUP== accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] VOLUMUP ..\n");
                                //input_report_key(kpd_accdet_dev, KEY_VOLUMEUP, 1);
                               // input_report_key(kpd_accdet_dev, KEY_VOLUMEUP, 0);
                               // input_sync(kpd_accdet_dev);
            }
      if(ACC_VOLUMEDOWN== accdet_key_event)
            {
                                ACCDET_DEBUG("[Accdet] VOLUMDOWN..\n");
                               // input_report_key(kpd_accdet_dev, KEY_VOLUMEDOWN, 1);
                                //input_report_key(kpd_accdet_dev, KEY_VOLUMEDOWN, 0);
                                //input_sync(kpd_accdet_dev);
            }




#endif
#ifdef JRD_HEADSET_MUSIC_KEY
            else if(ACC_MEDIA_PLAYPAUSE == accdet_key_event) {
                ACCDET_DEBUG("[Accdet] PLAY_PAUSE !\n");
                input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 1);
                input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 0);
                input_sync(kpd_accdet_dev);
            }
            else if(ACC_MEDIA_NEXT == accdet_key_event)
            {
                ACCDET_DEBUG("[Accdet] NEXT !\n");
                input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 1);
                input_report_key(kpd_accdet_dev, KEY_NEXTSONG, 0);
                input_sync(kpd_accdet_dev);
            }
#endif
        }
        atomic_set(&send_event_flag, 0);
      //  wake_unlock(&accdet_key_lock); //unlock wake lock
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值