这几天在写一个input驱动程序,功能是用一个中断读取三个按键的键值并且上报,自己的想法是在模块开启时开启一个等待线程并且睡眠,当中断到来时唤醒它用timer扫描按键值。写好烧进手机后手机一直无法开机,在启动时卡死并且重启。去掉这个等待线程程序就运行正常了,本人对等待线程这一块不是很理解,希望各位大神指导。另外,当读到键值的时候使用input_key_report函数上报的时候没有反应,不知道是不是设备注册有什么问题·····头好痛····
代码如下:
#include "ExternalPanel.h"
#include
//#include
#include
#include
#include
#define EXPANEL_NAME "external_panel"
#define KEY_PRESS_FLAG 1
#define KEY_RELEASE_FLAG 0
//#define KEY_NEXT_FLAG 1
//#define KEY_PAUSE_FLAG 2
#define KEY_PRESS_PAUSE 0
#define KEY_PRESS_UP 1
#define KEY_PRESS_DOWN 2
#define KEY_PRESS_NONE 3
/*
MD UP DW
|---------||-----------||----------|
0V<=MD< =0.2V 0.3V<= UP<=0.6V 0.8<=DW <=1.4V
*/
#define DW_KEY_HIGH_THR (1400) //1400000uv
#define DW_KEY_THR (800) //
#define UP_KEY_HIGH_THR (600) //
#define UP_KEY_THR (300)
#define MD_KEY_HIGH_THR (200)
#define MD_KEY_THR (0)
#define EXPANEL_KEY_ADC_CHANNEL 0
#define KEY_REF_VOLT 1500
static struct input_dev *expanel_input_dev;
struct workquenue_struct *expanel_eint_workquenue;
struct work_struct expanel_enit_work;
struct wake_lock expanel_irq_lock;
static struct hrtimer key_scan_timer;
static wait_queue_head_t scan_queue;
static struct task_struct *scan_kthread;
static int scan_state=0;
//static u8 expanel_state = !KPD_SLIDE_POLARITY;
static int expanel_input_open(struct input_dev dev);
extern void mt65xx_eint_unmask(unsigned int line);
extern void mt65xx_eint_mask(unsigned int line);
extern void mt65xx_eint_set_polarity(kal_uint8 eintno, kal_bool ACT_Polarity);
extern void mt65xx_eint_set_hw_debounce(kal_uint8 eintno, kal_uint32 ms);
extern kal_uint32 mt65xx_eint_set_sens(kal_uint8 eintno, kal_bool sens);
extern void mt65xx_eint_registration(kal_uint8 eintno, kal_bool Dbounce_En,
kal_bool ACT_Polarity, void (EINT_FUNC_PTR)(void),
kal_bool auto_umask);
static void expanel_eint_handler(void);
void expanel_eint_work_callback(struct work_struct *work);
int check_key_type(int b);
int getExPanelVoltage(void);
void report_key_event(int keycode,int flag);
static void expanel_key_detection(void);
//extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd);
extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int rawdata);
void key_scan_hrtimer_init(void);
enum hrtimer_restart key_scan_hrtimer_func(struct hrtimer *timer);
int key_wait_scan_thread(void *x);
int key_get_voltage(void);
static int expanel_probe(struct platform_device *pdev)
{
ExPanel_DEBUG("expanel_input!\n");
expanel_input_dev = input_allocate_device();
if (!expanel_input_dev)
{
ExPanel_DEBUG("expanel_input_device alloc failed!\n");
return 12;
}
//define multi-key keycode
set_bit(EV_KEY, expanel_input_dev->evbit);
//set_bit(KEY_CALL, expanel_input_dev->keybit);
//__set_bit(KEY_ENDCALL, expanel_input_dev->keybit);
// set_bit(KEY_NEXTSONG, expanel_input_dev->keybit);
// __set_bit(KEY_PREVIOUSSONG, expanel_input_dev->keybit);
__set_bit(KEY_PLAYPAUSE, expanel_input_dev->keybit);
//set_bit(KEY_STOPCD, expanel_input_dev->keybit);
__set_bit(KEY_VOLUMEDOWN, expanel_input_dev->keybit);
__set_bit(KEY_VOLUMEUP, expanel_input_dev->keybit);
expanel_input_dev->id.bustype = BUS_HOST;
expanel_input_dev->name = "expanel_key";
//expanel_input_dev->open = expanel_input_open;
expanel_input_dev->dev.parent = &pdev->dev;
if(input_register_device(expanel_input_dev))
{
ExPanel_DEBUG("expanel_input_dev register : fail!\n");
}else
{
ExPanel_DEBUG("expanel_input_devregister : success!!\n");
}
expanel_eint_workquenue = create_singlethread_workqueue("expanel_eint");
INIT_WORK(&expanel_enit_work, expanel_eint_work_callback);
wake_lock_init(&expanel_irq_lock, WAKE_LOCK_SUSPEND, "expanel irq wakelock");
scan_state=0;
mt65xx_eint_set_sens(CUST_EINT_EXPANEL_NUM , CUST_EINT_EXPANEL_SENSITIVE);
mt65xx_eint_set_hw_debounce(CUST_EINT_EXPANEL_NUM, 10);
mt65xx_eint_registration(CUST_EINT_EXPANEL_NUM, true, CUST_EINT_EXPANEL_POLARITY,
expanel_eint_handler, false);
mt65xx_eint_unmask(CUST_EINT_EXPANEL_NUM);
scan_kthread=kthread_run(key_wait_scan_thread, NULL, "key_wait_scan_thread");
return 0;
}
static int expanel_input_open(struct input_dev dev)
{
/
wake_lock_init(&expanel_irq_lock, WAKE_LOCK_SUSPEND, "expanel irq wakelock");
scan_state=0;
init_waitqueue_head(&scan_queue);
mt65xx_eint_set_sens(CUST_EINT_EXPANEL_NUM , CUST_EINT_EXPANEL_SENSITIVE);
mt65xx_eint_set_hw_debounce(CUST_EINT_EXPANEL_NUM, 10);
mt65xx_eint_registration(CUST_EINT_EXPANEL_NUM, true, CUST_EINT_EXPANEL_POLARITY,
expanel_eint_handler, false);
mt65xx_eint_unmask(CUST_EINT_EXPANEL_NUM);
key_wait_scan_thread();
*/
return 0;
}
void expanel_eint_handler(void)
{
ExPanel_DEBUG( " [ExPanel] expanel_key_handler \n");
/*
//mt65xx_eint_mask(CUST_EINT_EXPANEL_NUM);
scan_state=0;
//wake_up(&scan_queue);
wake_lock(&expanel_irq_lock);
// expanel_key_detection();
if(0==scan_state)
{
ExPanel_DEBUG("[Expanel] key_scan_hrtimer_init scan_state:%d\n",scan_state);
//wake_up_interruptible(&scan_queue);
wake_up(&scan_queue);
}
else
{
scan_state=0;
hrtimer_cancel(&key_scan_timer);
//mt65xx_eint_mask(CUST_EINT_EXPANEL_NUM);
}
//ExPanel_DEBUG( " [ExPanel] expanel_key_handler \n");
wake_unlock(&expanel_irq_lock);
ExPanel_DEBUG("[Expanel] Expanel_eint_handler ret:%d\n");
*/
int ret=0;
ret = queue_work(expanel_eint_workquenue, &expanel_enit_work);
if(!ret)
{
ExPanel_DEBUG("[Expanel] Expanel_eint_handler ret:%d\n",ret);
}
}
void expanel_eint_work_callback(struct work_struct *work)
{
//int key_type=0;
mt65xx_eint_mask(CUST_EINT_EXPANEL_NUM);
wake_lock(&expanel_irq_lock);
// wake_up_interruptible(&scan_queue);
// expanel_key_detection();
if(0==scan_state)
{
ExPanel_DEBUG("[Expanel] key_scan_hrtimer_init scan_state:%d\n",scan_state);
wake_up_interruptible(&scan_queue);
}
else
{
scan_state=0;
key_scan_hrtimer_init();
//mt65xx_eint_mask(CUST_EINT_EXPANEL_NUM);
}
//ExPanel_DEBUG( " [ExPanel] expanel_key_dection key_type:%d \n",key_type);
wake_unlock(&expanel_irq_lock);
mt65xx_eint_unmask(CUST_EINT_EXPANEL_NUM);
}
int key_wait_scan_thread(void x)
{
ktime_t ktime;
ktime = ktime_set(0, 100*1000*1000); // 3s, 10 1000 ms
hrtimer_init(&key_scan_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
key_scan_timer.function = key_scan_hrtimer_func;
/* Run on a process content */
// mutex_lock(&adckey_mutex);
// mutex_unlock(&adckey_mutex);
//battery_xlog_printk(BAT_LOG_CRTI, "adckey: wait_evnet \n" );
wait_event_interruptible(scan_queue, (0==scan_state));
scan_state=1;
//wait_event(scan_queue, (0==scan_state));
hrtimer_start(&key_scan_timer, ktime, HRTIMER_MODE_REL);
printk("[DEVICE/EXPANEL]:key_wait_scan_thread wake up!\n");
return 0;
}
void key_scan_hrtimer_init(void)
{
ktime_t ktime;
ktime = ktime_set(0, 100*1000*1000); // 3s, 10* 1000 ms
hrtimer_init(&key_scan_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
key_scan_timer.function = key_scan_hrtimer_func;
ExPanel_DEBUG( "key_scan_hrtimer_init : done\n" );
}
enum hrtimer_restart key_scan_hrtimer_func(struct hrtimer *timer)
{
ktime_t ktime;
ktime = ktime_set(0, 100*1000*1000);
ExPanel_DEBUG( " ExPanel_DEBUG: come in key_check!!\n" );
hrtimer_start(&key_scan_timer, ktime, HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
int check_key_type(int b)
{
ExPanel_DEBUG("cExPanel_DEBUG: come in key_check!!\n");
if((b<=DW_KEY_HIGH_THR)&&(b >= DW_KEY_THR))
{
ExPanel_DEBUG("ExPanel_DEBUG adc_data: %d mv\n",b);
return KEY_PRESS_DOWN;
}
else if ((b <=UP_KEY_HIGH_THR)&& (b >= UP_KEY_THR))
{
ExPanel_DEBUG("ExPanel_DEBUG adc_data: %d mv\n",b);
return KEY_PRESS_UP;
}
else if ((b <= MD_KEY_HIGH_THR) && (b >= MD_KEY_THR))
{
ExPanel_DEBUG("ExPanel_DEBUG adc_data: %d mv\n",b);
return KEY_PRESS_PAUSE;
}
ExPanel_DEBUG("ExPanel_DEBUG: leave key_check!!\n");
return KEY_PRESS_NONE;
}
void report_key_event(int keycode,int flag)
{
// if(call_status == 0)
// {
ExPanel_DEBUG(" report_key_event\n");
switch (keycode)
{
case KEY_PRESS_DOWN:
input_report_key(expanel_input_dev, KEY_VOLUMEDOWN, flag);
input_sync(expanel_input_dev);
ExPanel_DEBUG("KEY_NEXTSONG %d\n",flag);
break;
case KEY_PRESS_UP:
input_report_key(expanel_input_dev, KEY_VOLUMEUP, flag);
input_sync(expanel_input_dev);
ExPanel_DEBUG("KEY_PREVIOUSSONG %d\n",flag);
case KEY_PRESS_PAUSE:
input_report_key(expanel_input_dev,KEY_PLAYPAUSE, flag);
input_sync(expanel_input_dev);
ExPanel_DEBUG("KEY_PAUSE %d\n",flag);
break;
}
}
#if 0
else
{
switch (keycode)
{
case DW_KEY:
input_report_key(expanel_input_dev, KEY_VOLUMEDOWN, flag);
input_sync(expanel_input_dev);
ACCDET_DEBUG("KEY_VOLUMEDOWN %d\n",flag);
break;
case UP_KEY:
input_report_key(expanel_input_dev, KEY_VOLUMEUP, flag);
input_sync(expanel_input_dev);
ACCDET_DEBUG("KEY_VOLUMEUP %d\n",flag);
break;
}
}
#endif
}
static void expanel_key_detection(void)
{
//int current_status = 0;
//int index = 0;
//int count = long_press_time / (KEY_SAMPLE_PERIOD + 40 ); //ADC delay
int m_key = 0;
//int cur_key = 0;
int cali_voltage=0;
ExPanel_DEBUG("[ExPanel_DEBUG] expanel_key_detection! \n");
//cali_voltage = getExPanelVoltage();
cali_voltage=key_get_voltage();
ExPanel_DEBUG("[ExPanel_DEBUG]adc cali_voltage1 = %d mv\n", cali_voltage);
//ACCDET_DEBUG("[Accdet]adc cali_voltage final = %d mv\n", cali_voltage);
m_key= check_key_type(cali_voltage);
//
report_key_event(m_key, KEY_PRESS_FLAG);
report_key_event(m_key, KEY_RELEASE_FLAG);
}
int key_get_voltage(void)
{
int i = 0, bat_id_vol = 0, data[4] = {0,0,0,0};
int res =0;
int rawdata=0;
for(i = 0; i < 3; i++)
{
res = IMM_GetOneChannelValue(EXPANEL_KEY_ADC_CHANNEL,data,&rawdata);
if(res < 0)
{
printk("[DEVICE/EXPANEL]: get data error\n");
break;
}
else
{
printk("[DEVICE/EXPANEL]: channel0[%d]raw =%d\n",i,rawdata);
}
msleep(5);
bat_id_vol += (rawdata * KEY_REF_VOLT / 4096);
printk("DEVICE/EXPANEL: channel0[%d]vol =%d\n",i,rawdata * KEY_REF_VOLT / 4096);
}
if(res < 0) /*get adc value fail*/
return;
bat_id_vol = bat_id_vol/3;
return bat_id_vol;
}
static int expanel_remove(struct platform_device *pdev)
{
//cancel_delayed_work(&accdet_work);
kthread_stop(scan_kthread);
hrtimer_cancel(&key_scan_timer);
destroy_workqueue(expanel_eint_workquenue);
input_unregister_device(expanel_input_dev);
ExPanel_DEBUG("[ExPanel_DEBUG]ExPanel_remove Done!\n");
return 0;
}
static struct platform_device expanel_dev = {
.name = EXPANEL_NAME,
.id = -1,
};
static struct platform_driver expanel_drv = {
.probe = expanel_probe,
.remove = expanel_remove,
.driver = {
.name = EXPANEL_NAME,
.owner= THIS_MODULE,
},
};
static int __init expanel_mod_init(void)
{
ExPanel_DEBUG("expanel_input_device init!\n");
platform_device_register(&expanel_dev );
platform_driver_register(& expanel_drv );
return 0;
}
static void __exit expanel_mod_exit(void)
{
platform_device_unregister(&expanel_dev);
platform_driver_unregister(& expanel_drv );
}
module_init(expanel_mod_init);
module_exit(expanel_mod_exit);
MODULE_LICENSE("GPL");