input_report_XXX函数

本文详细解析了Linux输入子系统的工作原理,包括input_report_XXX系列函数如何通告事件,input_event()函数的作用及流程,以及事件如何被分发到设备和处理程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

输入子系统设备通告各种事件通过input_report_XXX族函数
 
/* include/linux/input.h */
 
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
         input_event(dev, EV_KEY, code, !!value);
}
 
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
         input_event(dev, EV_REL, code, value);
}
 
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
         input_event(dev, EV_ABS, code, value);
}
 
static inline void input_sync(struct input_dev *dev)
{
         input_event(dev, EV_SYN, SYN_REPORT, 0);
}
可以看到,这四个函数都调用了input_event。这些API 其实都是input_event()的封装.代码如下:

void input_event(struct input_dev *dev,
 unsigned int type, unsigned int code, int value)
{
 unsigned long flags;
 
 if (is_event_supported(type, dev->evbit, EV_MAX)) {
 
 spin_lock_irqsave(&dev->event_lock, flags);
 add_input_randomness(type, code, value);//由于输入事件具有随机性,因此用输入事件来增加内核熵池的熵
 input_handle_event(dev, type, code, value);//调用事件分发函数input_handle_event,做进一步的传递
 spin_unlock_irqrestore(&dev->event_lock, flags);
 }
}
首先,先判断设备产生的这个事件是否合法.如果合法,流程转入到input_handle_event()中.

/* driver/input/input.c */
 
#define INPUT_IGNORE_EVENT         0
 
#define INPUT_PASS_TO_HANDLERS     1
 
#define INPUT_PASS_TO_DEVICE       2
 
#define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
static void input_handle_event(struct input_dev *dev,
 unsigned int type, unsigned int code, int value)
{
 int disposition = INPUT_IGNORE_EVENT;
 
 switch (type) {
 
 case EV_SYN:
 switch (code) {
 case SYN_CONFIG:
 disposition = INPUT_PASS_TO_ALL;
 break;
 
 case SYN_REPORT:
 if (!dev->sync) {
 dev->sync = 1;
 disposition = INPUT_PASS_TO_HANDLERS;
 }
 break;
 case SYN_MT_REPORT:
 dev->sync = 0;
 disposition = INPUT_PASS_TO_HANDLERS;
 break;
 }
 break;
 
 case EV_KEY:
 if (is_event_supported(code, dev->keybit, KEY_MAX) &&//检查按键是否为驱动所支持,只有之前注册过的按键才会继续传递
 !!test_bit(code, dev->key) != value) {//检查报告的按键状态是否和上次相同。如果连续多次报告按键按下,则只处理第一次
 
 if (value != 2) {//如果不是连击事件
 __change_bit(code, dev->key);//翻转按键的当前状态(按下和释放)
 if (value)
 input_start_autorepeat(dev, code);
 else
 input_stop_autorepeat(dev);
 }
 
 disposition = INPUT_PASS_TO_HANDLERS;//标记消息传递方向
 }
 break;
 
 case EV_SW:
 if (is_event_supported(code, dev->swbit, SW_MAX) &&
 !!test_bit(code, dev->sw) != value) {
 
 __change_bit(code, dev->sw);
 disposition = INPUT_PASS_TO_HANDLERS;
 }
 break;
 
 case EV_ABS:
 if (is_event_supported(code, dev->absbit, ABS_MAX)) {//检查绝对坐标轴是否驱动所支持的
 
 if (test_bit(code, input_abs_bypass)) {
 disposition = INPUT_PASS_TO_HANDLERS;
 break;
 }
 
 value = input_defuzz_abs_event(value,
 dev->abs[code], dev->absfuzz[code]);//根据当前报告的值和上次报告的值确定传给处理程序的绝对值大小
 
 if (dev->abs[code] != value) {//如果本次需要报告的绝对值和上次不同,则将事件传递给处理函数
 dev->abs[code] = value;
 disposition = INPUT_PASS_TO_HANDLERS;
 }
 }
 break;
 
 case EV_REL:
 if (is_event_supported(code, dev->relbit, REL_MAX) && value)//检查相对坐标轴是否被驱动所支持
 disposition = INPUT_PASS_TO_HANDLERS;
 
 break;
 
 case EV_MSC:
 if (is_event_supported(code, dev->mscbit, MSC_MAX))
 disposition = INPUT_PASS_TO_ALL;
 
 break;
 
 case EV_LED:
 if (is_event_supported(code, dev->ledbit, LED_MAX) &&
 !!test_bit(code, dev->led) != value) {
 
 __change_bit(code, dev->led);
 disposition = INPUT_PASS_TO_ALL;
 }
 break;
 
 case EV_SND:
 if (is_event_supported(code, dev->sndbit, SND_MAX)) {
 
 if (!!test_bit(code, dev->snd) != !!value)
 __change_bit(code, dev->snd);
 disposition = INPUT_PASS_TO_ALL;
 }
 break;
 
 case EV_REP:
 if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
 dev->rep[code] = value;
 disposition = INPUT_PASS_TO_ALL;
 }
 break;
 
 case EV_FF:
 if (value >= 0)
 disposition = INPUT_PASS_TO_ALL;
 break;
 
 case EV_PWR:
 disposition = INPUT_PASS_TO_ALL;
 break;
 }
 
 if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
 dev->sync = 0;
 
 if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
 dev->event(dev, type, code, value);
 
 if (disposition & INPUT_PASS_TO_HANDLERS)
 input_pass_event(dev, type, code, value);
}
在这里,我们忽略掉具体事件的处理.到最后,如果该事件需要input device 来完成的,就会将disposition 设置成INPUT_PASS_TO_DEVICE.如果需要handler 来完成的,就将dispostion 设为INPUT_PASS_TO_HANDLERS.如果需要两者都参与,将disposition 设置为INPUT_PASS_TO_ALL.需要输入设备参与的,回调设备的event 函数.如果需要handler 参与的.调用input_pass_event()

static void input_pass_event(struct input_dev *dev,
 unsigned int type, unsigned int code, int value)
{
 struct input_handle *handle;
 
 rcu_read_lock();
 
 handle = rcu_dereference(dev->grab);//获取独占设备的handle的指针
 if (handle)
 handle->handler->event(handle, type, code, value);//如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler
 else
 list_for_each_entry_rcu(handle, &dev->h_list, d_node)//遍历与此设备连接的每一个handle
 if (handle->open)//如果handle已经打开
 handle->handler->event(handle,
 type, code, value);//将事件分发给handler的事件处理函数
 rcu_read_unlock();
}
如果input device 被强制指定了handler,则调用该handler 的event 函数.结合handle 注册的分析.我们知道.会将handle 挂到input device 的h_list 链表上.如果没有为input device 强制指定handler.就会遍历input device->h_list 上的handle 成员.如果该handle 被打开,则调用与输入设备对应的handler 的event()函数.注意,只有在handle 被打开的情况下才会接收到事件.另外,输入设备的handler 强制设置一般是用带EVIOCGRAB 标志的ioctl 来完成的.如下是发图的方示总结evnet 的处理过程:

 

 

static void send_accdet_status_event(int cable_type, int status) 664 { 665 switch (cable_type) { 666 case HEADSET_NO_MIC: 667 input_report_switch(kpd_accdet_dev, SW_HEADPHONE_INSERT, status); 668 input_report_switch(kpd_accdet_dev, SW_JACK_PHYSICAL_INSERT, status); 669 input_sync(kpd_accdet_dev); 670 ACCDET_DEBUG("[Accdet]HEADSET_NO_MIC(3-pole) %s\n", status?"PlugIn":"PlugOut"); 671 break; 672 case HEADSET_MIC: 673 input_report_switch(kpd_accdet_dev, SW_HEADPHONE_INSERT, status); 674 input_report_switch(kpd_accdet_dev, SW_MICROPHONE_INSERT, status); 675 input_report_switch(kpd_accdet_dev, SW_JACK_PHYSICAL_INSERT, status); 676 input_sync(kpd_accdet_dev); 677 ACCDET_DEBUG("[Accdet]HEADSET_MIC(4-pole) %s\n", status?"PlugIn":"PlugOut"); 678 break; 679 default: 680 ACCDET_DEBUG("[Accdet]Invalid cableType\n"); 681 } 682 } 683 684 static void send_key_event(int keycode, int flag) 685 { 686 switch (keycode) { 687 case DW_KEY: 688 input_report_key(kpd_accdet_dev, KEY_VOLUMEDOWN, flag); 689 input_sync(kpd_accdet_dev); 690 ACCDET_DEBUG("[accdet]KEY_VOLUMEDOWN %d\n", flag); 691 break; 692 case UP_KEY: 693 input_report_key(kpd_accdet_dev, KEY_VOLUMEUP, flag); 694 input_sync(kpd_accdet_dev); 695 ACCDET_DEBUG("[accdet]KEY_VOLUMEUP %d\n", flag); 696 break; 697 case MD_KEY: 698 input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, flag); 699 input_sync(kpd_accdet_dev); 700 ACCDET_DEBUG("[accdet]KEY_PLAYPAUSE %d\n", flag); 701 break; 702 case AS_KEY: 703 input_report_key(kpd_accdet_dev, KEY_VOICECOMMAND, flag); 704 input_sync(kpd_accdet_dev); 705 ACCDET_DEBUG("[accdet]KEY_VOICECOMMAND %d\n", flag); 706 break; 707 } 708 } 709 710 static void multi_key_detection(int current_status) 711 { 712 int m_key = 0; 713 int cali_voltage = 0; 714 715 if (0 == current_status) { 716 cali_voltage = Accdet_PMIC_IMM_GetOneChannelValue(1); 717 /*ACCDET_DEBUG("[Accdet]adc cali_voltage1 = %d mv\n", cali_voltage);*/ 718 m_key = cur_key = key_check(cali_voltage); 719 } 720 mdelay(30); 721 #ifdef CONFIG_ACCDET_EINT_IRQ 722 if (((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) != EINT_IRQ_STATUS_BIT) || eint_accdet_sync_flag) { 723 #else /* ifdef CONFIG_ACCDET_EINT */ 724 if (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) != IRQ_STATUS_BIT) || eint_accdet_sync_flag) { 725 #endif 726 send_key_event(cur_key, !current_status); 727 } else { 728 ACCDET_DEBUG("[Accdet]plug out side effect key press, do not report key = %d\n", cur_key); 729 cur_key = NO_KEY; 730 } 731 if (current_status) 732 cur_key = NO_KEY; 733 } 734 #endif 735 static void accdet_workqueue_func(void) 736 { 737 int ret; 738 739 ret = queue_work(accdet_workqueue, &accdet_work); 740 if (!ret) 741 ACCDET_DEBUG("[Accdet]accdet_work return:%d!\n", ret); 742 } 743 744 int accdet_irq_handler(void) 745 { 746 u64 cur_time = 0; 747 748 cur_time = accdet_get_current_time(); 749 750 #ifdef CONFIG_ACCDET_EINT_IRQ 751 ACCDET_DEBUG("[Accdet accdet_irq_handler]clear_accdet_eint_interrupt: ACCDET_IRQ_STS = 0x%x\n", 752 pmic_pwrap_read(ACCDET_IRQ_STS)); 753 if ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) 754 && ((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) != EINT_IRQ_STATUS_BIT)) { 755 clear_accdet_interrupt(); 756 if (accdet_status == MIC_BIAS) { 757 /*accdet_auxadc_switch(1);*/ 758 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 759 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 760 } 761 accdet_workqueue_func(); 762 while (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) 763 && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT)))) 764 ; 765 } else if ((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) == EINT_IRQ_STATUS_BIT) { 766 if (cur_eint_state == EINT_PIN_PLUG_IN) { 767 if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH) 768 pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) | EINT_IRQ_POL_HIGH); 769 else 770 pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & ~EINT_IRQ_POL_LOW); 771 } else { 772 if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH) 773 pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & ~EINT_IRQ_POL_LOW); 774 else 775 pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) | EINT_IRQ_POL_HIGH); 776 } 777 clear_accdet_eint_interrupt(); 778 while (((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) 779 && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT)))) 780 ; 781 accdet_eint_func(accdet_irq, NULL); 782 } else { 783 ACCDET_DEBUG("ACCDET IRQ and EINT IRQ don't be triggerred!!\n"); 784 } 785 #else 786 if ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)) 787 clear_accdet_interrupt(); 788 if (accdet_status == MIC_BIAS) { 789 /*accdet_auxadc_switch(1);*/ 790 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 791 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 792 } 793 accdet_workqueue_func(); 794 while (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) 795 && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT)))) 796 ; 797 #endif 798 #ifdef ACCDET_NEGV_IRQ 799 cur_time = accdet_get_current_time(); 800 if ((pmic_pwrap_read(ACCDET_IRQ_STS) & NEGV_IRQ_STATUS_BIT) == NEGV_IRQ_STATUS_BIT) { 801 ACCDET_DEBUG("[ACCDET NEGV detect]plug in a error Headset\n\r"); 802 pmic_pwrap_write(ACCDET_IRQ_STS, (IRQ_NEGV_CLR_BIT)); 803 while (((pmic_pwrap_read(ACCDET_IRQ_STS) & NEGV_IRQ_STATUS_BIT) 804 && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT)))) 805 ; 806 pmic_pwrap_write(ACCDET_IRQ_STS, (pmic_pwrap_read(ACCDET_IRQ_STS) & (~IRQ_NEGV_CLR_BIT))); 807 } 808 #endif 809 810 return 1; 811 }
最新发布
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值