走在前面的人有饭吃,走在后面的人没饭吃,技术先人一步,你就是赢家,欢迎到未来新技术手机操作系统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;
}