do_IRQ 函数细节

//
// do_IRQ 函数执行完硬件 ISR 后退出时调用此函数。
//
void irq_exit(void)
{
        account_system_vtime(current);
        trace_hardirq_exit();
        sub_preempt_count(IRQ_EXIT_OFFSET);
        //
        // 判断当前是否有硬件中断嵌套,并且是否有软中断在
        // pending 状态,注意:这里只有两个条件同时满足
        // 时,才有可能调用 do_softirq() 进入软中断。也就是
        // 说确认当前所有硬件中断处理完成,且有硬件中断安装了
        // 软中断处理时理时才会进入。
        // 
        if (!in_interrupt() && local_softirq_pending())
                //
                // 其实这里就是调用 do_softirq() 执行
                //
                invoke_softirq();
        preempt_enable_no_resched();
}
#ifndef __ARCH_HAS_DO_SOFTIRQ
asmlinkage void do_softirq(void)
{
        __u32 pending;
        unsigned long flags;
        //
        // 这个函数判断,如果当前有硬件中断嵌套,或者
        // 有软中断正在执行时候,则马上返回。在这个
        // 入口判断主要是为了与 ksoftirqd 互斥。
        //
        if (in_interrupt())
                return;
        //
        // 关中断执行以下代码
        //
        local_irq_save(flags);
        //
        // 判断是否有 pending 的软中断需要处理。
        //
        pending = local_softirq_pending();
        //
        // 如果有则调用 __do_softirq() 进行实际处理
        //
        if (pending)
                __do_softirq();
        //
        // 开中断继续执行
        //
        local_irq_restore(flags);
}
//
// 最大软中断调用次数为 10 次。
//
#define MAX_SOFTIRQ_RESTART 10
asmlinkage void __do_softirq(void)
{
        //
        // 软件中断处理结构,此结构中包括了 ISR 中
        // 注册的回调函数。
        //
        struct softirq_action *h;
        __u32 pending;
        int max_restart = MAX_SOFTIRQ_RESTART;
        int cpu;
        //
        // 得到当前所有 pending 的软中断。
        // 
        pending = local_softirq_pending();
        account_system_vtime(current);
        //
        // 执行到这里要屏蔽其他软中断,这里也就证明了
        // 每个 CPU 上同时运行的软中断只能有一个。
        //
        __local_bh_disable((unsigned long)__builtin_return_address(0));
        trace_softirq_enter();
        //
        // 针对 SMP 得到当前正在处理的 CPU
        //
        cpu = smp_processor_id();
//
// 循环标志
//
restart:
        //
        // 每次循环在允许硬件 ISR 强占前,首先重置软中断
        // 的标志位。
        //
        /* Reset the pending bitmask before enabling irqs */
        set_softirq_pending(0);
        //
        // 到这里才开中断运行,注意:以前运行状态一直是关中断
        // 运行,这时当前处理软中断才可能被硬件中断抢占。也就
        // 是说在进入软中断时不是一开始就会被硬件中断抢占。只有
        // 在这里以后的代码才可能被硬件中断抢占。
        //
        local_irq_enable();
        //
        // 这里要注意,以下代码运行时可以被硬件中断抢占,但
        // 这个硬件 ISR 执行完成后,它的所注册的软中断无法马上运行,
        // 别忘了,现在虽是开硬件中断执行,但前面的 __local_bh_disable()
        // 函数屏蔽了软中断。所以这种环境下只能被硬件中断抢占,但这
        // 个硬中断注册的软中断回调函数无法运行。要问为什么,那是因为
        // __local_bh_disable() 函数设置了一个标志当作互斥量,而这个
        // 标志正是上面的 irq_exit() 和 do_softirq() 函数中的
        // in_interrupt() 函数判断的条件之一,也就是说 in_interrupt() 
        // 函数不仅检测硬中断而且还判断了软中断。所以在这个环境下触发
        // 硬中断时注册的软中断,根本无法重新进入到这个函数中来,只能
        // 是做一个标志,等待下面的重复循环(最大 MAX_SOFTIRQ_RESTART)
        // 才可能处理到这个时候触发的硬件中断所注册的软中断。
        //
        //
        // 得到软中断向量表。
        //
        h = softirq_vec;
        //
        // 循环处理所有 softirq 软中断注册函数。
        // 
        do {
                //
                // 如果对应的软中断设置 pending 标志则表明
                // 需要进一步处理它所注册的函数。
                //
                if (pending & 1) {
                        //
                        // 在这里执行了这个软中断所注册的回调函数。
                        //
                        h->action(h);
                        rcu_bh_qsctr_inc(cpu);
                }
        //
        // 继续找,直到把软中断向量表中所有 pending 的软
        // 中断处理完成。
        //
                h++;
                //
                // 从代码里可以看出按位操作,表明一次循环只
                // 处理 32 个软中断的回调函数。
                //
                pending >>= 1; 
        } while (pending);
        //
        // 关中断执行以下代码。注意:这里又关中断了,下面的
        // 代码执行过程中硬件中断无法抢占。
        //
        local_irq_disable();
        //
        // 前面提到过,在刚才开硬件中断执行环境时只能被硬件中断
        // 抢占
/*clear ACCDET IRQ in accdet register*/ 814 static inline void clear_accdet_interrupt(void) 815 { 816 /*it is safe by using polling to adjust when to clear IRQ_CLR_BIT*/ 817 pmic_pwrap_write(ACCDET_IRQ_STS, ((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | (IRQ_CLR_BIT)); 818 ACCDET_DEBUG("[Accdet]clear_accdet_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 819 } 820 821 static inline void clear_accdet_eint_interrupt(void) 822 { 823 pmic_pwrap_write(ACCDET_IRQ_STS, (((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | IRQ_EINT_CLR_BIT)); 824 ACCDET_DEBUG("[Accdet]clear_accdet_eint_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 825 } 826 827 static inline void check_cable_type(void) 828 { 829 int current_status = 0; 830 int irq_temp = 0; /*for clear IRQ_bit*/ 831 int wait_clear_irq_times = 0; 832 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 833 int pin_adc_value = 0; 834 #define PIN_ADC_CHANNEL 5 835 #endif 836 837 current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/ 838 ACCDET_DEBUG("[Accdet]accdet interrupt happen:[%s]current AB = %d\n", 839 accdet_status_string[accdet_status], current_status); 840 841 button_status = 0; 842 pre_status = accdet_status; 843 844 /*ACCDET_DEBUG("[Accdet]check_cable_type: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));*/ 845 IRQ_CLR_FLAG = false; 846 switch (accdet_status) { 847 case PLUG_OUT: 848 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 849 pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1); 850 #endif 851 if (current_status == 0) { 852 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 853 /*micbias always on during detected PIN recognition*/ 854 pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); 855 pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width); 856 ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n"); 857 ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value); 858 msleep(500); 859 current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/ 860 if (current_status == 0 && show_icon_delay != 0) { 861 /*accdet_auxadc_switch(1);switch on when need to use auxadc read voltage*/ 862 pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1); 863 ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value); 864 /*accdet_auxadc_switch(0);*/ 865 if (180 > pin_adc_value && pin_adc_value > 90) { /*90mv ilegal headset*/ 866 /*mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ONE);*/ 867 /*ACCDET_DEBUG("[Accdet]PIN recognition change GPIO_OUT!\n");*/ 868 mutex_lock(&accdet_eint_irq_sync_mutex); 869 if (1 == eint_accdet_sync_flag) { 870 cable_type = HEADSET_NO_MIC; 871 accdet_status = HOOK_SWITCH; 872 cable_pin_recognition = 1; 873 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", 874 cable_pin_recognition); 875 } else { 876 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 877 } 878 mutex_unlock(&accdet_eint_irq_sync_mutex); 879 } else { 880 mutex_lock(&accdet_eint_irq_sync_mutex); 881 if (1 == eint_accdet_sync_flag) { 882 cable_type = HEADSET_NO_MIC; 883 accdet_status = HOOK_SWITCH; 884 } else { 885 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 886 } 887 mutex_unlock(&accdet_eint_irq_sync_mutex); 888 } 889 } 890 #else 891 mutex_lock(&accdet_eint_irq_sync_mutex); 892 if (1 == eint_accdet_sync_flag) { 893 cable_type = HEADSET_NO_MIC; 894 accdet_status = HOOK_SWITCH; 895 } else { 896 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 897 } 898 mutex_unlock(&accdet_eint_irq_sync_mutex); 899 #endif 900 } else if (current_status == 1) { 901 mutex_lock(&accdet_eint_irq_sync_mutex); 902 if (1 == eint_accdet_sync_flag) { 903 accdet_status = MIC_BIAS; 904 cable_type = HEADSET_MIC; 905 /*AB=11 debounce=30ms*/ 906 pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3 * 30); 907 } else { 908 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 909 } 910 mutex_unlock(&accdet_eint_irq_sync_mutex); 911 pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); 912 /*recover polling set AB 00-01*/ 913 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 914 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 915 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 916 #endif 917 } else if (current_status == 3) { 918 ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n"); 919 #ifdef CONFIG_ACCDET_EINT 920 ACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n"); 921 #else 922 mutex_lock(&accdet_eint_irq_sync_mutex); 923 if (1 == eint_accdet_sync_flag) { 924 accdet_status = PLUG_OUT; 925 cable_type = NO_DEVICE; 926 } else { 927 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 928 } 929 mutex_unlock(&accdet_eint_irq_sync_mutex); 930 #endif 931 } else { 932 ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n"); 933 } 934 break; 935 936 case MIC_BIAS: 937 /*solution: resume hook switch debounce time*/ 938 pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0); 939 940 if (current_status == 0) { 941 mutex_lock(&accdet_eint_irq_sync_mutex); 942 if (1 == eint_accdet_sync_flag) { 943 while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) 944 && (wait_clear_irq_times < 3)) { 945 ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n"); 946 wait_clear_irq_times++; 947 msleep(20); 948 } 949 irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); 950 irq_temp = irq_temp & (~IRQ_CLR_BIT); 951 pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); 952 IRQ_CLR_FLAG = true; 953 accdet_status = HOOK_SWITCH; 954 } else { 955 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 956 } 957 mutex_unlock(&accdet_eint_irq_sync_mutex); 958 button_status = 1; 959 if (button_status) { 960 mutex_lock(&accdet_eint_irq_sync_mutex); 961 if (1 == eint_accdet_sync_flag) 962 multi_key_detection(current_status); 963 else 964 ACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n"); 965 mutex_unlock(&accdet_eint_irq_sync_mutex); 966 /*accdet_auxadc_switch(0);*/ 967 /*recover pwm frequency and duty*/ 968 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 969 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 970 } 971 } else if (current_status == 1) { 972 mutex_lock(&accdet_eint_irq_sync_mutex); 973 if (1 == eint_accdet_sync_flag) { 974 accdet_status = MIC_BIAS; 975 cable_type = HEADSET_MIC; 976 ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n"); 977 } else { 978 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 979 } 980 mutex_unlock(&accdet_eint_irq_sync_mutex); 981 } else if (current_status == 3) { 982 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 983 ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n"); 984 mutex_lock(&accdet_eint_irq_sync_mutex); 985 if (1 == eint_accdet_sync_flag) 986 accdet_status = PLUG_OUT; 987 else 988 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 989 mutex_unlock(&accdet_eint_irq_sync_mutex); 990 #else 991 mutex_lock(&accdet_eint_irq_sync_mutex); 992 if (1 == eint_accdet_sync_flag) { 993 accdet_status = PLUG_OUT; 994 cable_type = NO_DEVICE; 995 } else { 996 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 997 } 998 mutex_unlock(&accdet_eint_irq_sync_mutex); 999 #endif 1000 } else { 1001 ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n"); 1002 } 1003 break; 1004 1005 case HOOK_SWITCH: 1006 if (current_status == 0) { 1007 mutex_lock(&accdet_eint_irq_sync_mutex); 1008 if (1 == eint_accdet_sync_flag) { 1009 /*for avoid 01->00 framework of Headset will report press key info for Audio*/ 1010 /*cable_type = HEADSET_NO_MIC;*/ 1011 /*accdet_status = HOOK_SWITCH;*/ 1012 ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n"); 1013 } else { 1014 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1015 } 1016 mutex_unlock(&accdet_eint_irq_sync_mutex); 1017 } else if (current_status == 1) { 1018 mutex_lock(&accdet_eint_irq_sync_mutex); 1019 if (1 == eint_accdet_sync_flag) { 1020 multi_key_detection(current_status); 1021 accdet_status = MIC_BIAS; 1022 cable_type = HEADSET_MIC; 1023 } else { 1024 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1025 } 1026 mutex_unlock(&accdet_eint_irq_sync_mutex); 1027 /*accdet_auxadc_switch(0);*/ 1028 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 1029 cable_pin_recognition = 0; 1030 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); 1031 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 1032 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 1033 #endif 1034 /*solution: reduce hook switch debounce time to 0x400*/ 1035 pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); 1036 } else if (current_status == 3) { 1037 1038 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 1039 cable_pin_recognition = 0; 1040 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); 1041 mutex_lock(&accdet_eint_irq_sync_mutex); 1042 if (1 == eint_accdet_sync_flag) 1043 accdet_status = PLUG_OUT; 1044 else 1045 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1046 mutex_unlock(&accdet_eint_irq_sync_mutex); 1047 #endif 1048 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 1049 ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n"); 1050 mutex_lock(&accdet_eint_irq_sync_mutex); 1051 if (1 == eint_accdet_sync_flag) 1052 accdet_status = PLUG_OUT; 1053 else 1054 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1055 mutex_unlock(&accdet_eint_irq_sync_mutex); 1056 #else 1057 mutex_lock(&accdet_eint_irq_sync_mutex); 1058 if (1 == eint_accdet_sync_flag) { 1059 accdet_status = PLUG_OUT; 1060 cable_type = NO_DEVICE; 1061 } else { 1062 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1063 } 1064 mutex_unlock(&accdet_eint_irq_sync_mutex); 1065 #endif 1066 } else { 1067 ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n"); 1068 } 1069 break; 1070 case STAND_BY: 1071 if (current_status == 3) { 1072 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 1073 ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n"); 1074 #else 1075 mutex_lock(&accdet_eint_irq_sync_mutex); 1076 if (1 == eint_accdet_sync_flag) { 1077 accdet_status = PLUG_OUT; 1078 cable_type = NO_DEVICE; 1079 } else { 1080 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1081 } 1082 mutex_unlock(&accdet_eint_irq_sync_mutex); 1083 #endif 1084 } else { 1085 ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n"); 1086 } 1087 break; 1088 1089 default: 1090 ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n"); 1091 break; 1092 1093 } 1094 1095 if (!IRQ_CLR_FLAG) { 1096 mutex_lock(&accdet_eint_irq_sync_mutex); 1097 if (1 == eint_accdet_sync_flag) { 1098 while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times < 3)) { 1099 ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going2....\n"); 1100 wait_clear_irq_times++; 1101 msleep(20); 1102 } 1103 } 1104 irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); 1105 irq_temp = irq_temp & (~IRQ_CLR_BIT); 1106 pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); 1107 mutex_unlock(&accdet_eint_irq_sync_mutex); 1108 IRQ_CLR_FLAG = true; 1109 ACCDET_DEBUG("[Accdet]check_cable_type:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 1110 1111 } else { 1112 IRQ_CLR_FLAG = false; 1113 } 1114 1115 ACCDET_DEBUG("[Accdet]cable type:[%s], status switch:[%s]->[%s]\n", 1116 accdet_report_string[cable_type], accdet_status_string[pre_status], 1117 accdet_status_string[accdet_status]); 1118 }
07-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值