disable_irq与disable_irq_nosync使用场景
Linux设备驱动,关于中断屏蔽有两个接口:disable_irq和disable_irq_nosync,该两接口使用场景如下:
1、disable_irq:在非中断处理函数中使用,会阻塞;
2、disable_irq_nosync:在中断处理函数中使用,不会阻塞;用于屏蔽相应中断;
一、为什么要屏蔽中断?
使能中断后,一旦触发中断,系统会进入中断处理函数;如果下一个中断触发的时候,前一个中断处理函数已经完成,这是理想状态,不会发生异常;如果前一个中断处理函数还未完成,那么就会导致中断嵌套。为了不出现中断嵌套,必须在中断处理函数中屏蔽中断,待中断处理完成后,再主动使能中断。
二、disable_irq不能放在中断处理函数中
如果在中断处理函数中使用disable_irq屏蔽相应中断,系统将会出现死锁状态,最后死机,然后重启。(已验证)
三、enable_irq配套使用
当中断处理函数已经完成所有工作,在返回之前需要主动调用接口enable_irq使能中断,否则该中断将一直被屏蔽。(已验证)
四、附上距离传感器中断处理处理函数
//PS中断处理
static irqreturn_t ltr559_irq_handler(int irq, void *arg)
{
struct ltr559_data *data = (struct ltr559_data *)arg;
//printk("%s ",__func__);
if (NULL == data)
return IRQ_HANDLED;
//后面必须有使能中断
disable_irq_nosync(data->irq); //屏蔽中断,不会造成死锁
schedule_delayed_work(&data->ps_work, 0); //调用延时工作队列
return IRQ_HANDLED;
}
static irqreturn_t ltr559_irq_handler(int irq, void *arg)
{
struct ltr559_data *data = (struct ltr559_data *)arg;
//printk("%s ",__func__);
if (NULL == data)
return IRQ_HANDLED;
//后面必须有使能中断
disable_irq_nosync(data->irq); //屏蔽中断,不会造成死锁
schedule_delayed_work(&data->ps_work, 0); //调用延时工作队列
return IRQ_HANDLED;
}
//PS工作任务
//重要接口
static void ltr559_ps_work_func(struct work_struct *work)
{
struct ltr559_data *data = container_of(work, struct ltr559_data, ps_work.work);
struct i2c_client *client=data->client;
int als_ps_status;
int psval_lo, psval_hi, psdata;
static u32 ps_state_last = 2; //Far as default.
mutex_lock(&data->op_lock);
als_ps_status = i2c_smbus_read_byte_data(client, LTR559_ALS_PS_STATUS);
//printk("%s ps_open_state=%d, als_ps_status=0x%x ",__func__,data->ps_open_state,als_ps_status);
if (als_ps_status < 0)
goto workout;
/* Here should check data status,ignore interrupt status. */
/* Bit 0: PS Data
* Bit 1: PS interrupt
* Bit 2: ASL Data
* Bit 3: ASL interrupt
* Bit 4: ASL Gain 0: ALS measurement data is in dynamic range 2 (2 to 64k lux)
* 1: ALS measurement data is in dynamic range 1 (0.01 to 320 lux)
*/
//使能情况
if ((data->ps_open_state == 1) && (als_ps_status & 0x02)) {
psval_lo = i2c_smbus_read_byte_data(client, LTR559_PS_DATA_0);
if (psval_lo < 0) {
psdata = psval_lo;
goto workout;
}
psval_hi = i2c_smbus_read_byte_data(client, LTR559_PS_DATA_1);
if (psval_hi < 0) {
psdata = psval_hi;
goto workout;
}
psdata = ((psval_hi & 7) << 8) | psval_lo;
printk("%s: psdata=%d(0x%x), near_thrd=%u, far_thrd=%u, dynamic_noise=%u ",
__func__, psdata, (u32)psdata, data->platform_data->prox_threshold,
data->platform_data->prox_hsyteresis_threshold, data->dynamic_noise);
if(psdata >= data->platform_data->prox_threshold){
data->ps_state = 0; //near
ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold);
ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x07ff);
printk("%s: near, update near_thrd=%u, far_thrd=%u ",
__func__, 0x7ff, data->platform_data->prox_hsyteresis_threshold);
} else if (psdata <= data->platform_data->prox_hsyteresis_threshold){
data->ps_state = 1; //far
//该宏已经定义
#if defined(CONFIG_PICCOLO_COMMON)
if (data->dynamic_noise > 20 && psdata < (data->dynamic_noise - 50) ) {
data->dynamic_noise = psdata;
if(psdata < 100) {
}else if(psdata < 200){
data->platform_data->prox_threshold = psdata+230;
data->platform_data->prox_hsyteresis_threshold = psdata+180;
}else if(psdata < 500){
data->platform_data->prox_threshold = psdata+280;
data->platform_data->prox_hsyteresis_threshold = psdata+230;
}else if(psdata < 1500){
data->platform_data->prox_threshold = psdata+420;
data->platform_data->prox_hsyteresis_threshold = psdata+350;
}else{
data->platform_data->prox_threshold= 1800;
data->platform_data->prox_hsyteresis_threshold= 1700;
pr_err("ltr559 the proximity sensor rubber or structure is error! ");
}
printk("%s: NEW prox_threshold=%u, prox_hsyteresis_threshold=%u !!! ",
__func__, data->platform_data->prox_threshold,
data->platform_data->prox_hsyteresis_threshold);
}
#endif
ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0);
ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold);
printk("%s: far, update near_thrd=%u, far_thrd=0 ",
__func__, data->platform_data->prox_threshold);
} else {
data->ps_state = ps_state_last;
}
printk("%s: ps_state_last = %u, ps_state = %u ", __func__, ps_state_last, data->ps_state);
if((ps_state_last != data->ps_state) || (data->ps_state == 0)) //need report the input event constant when near
{
//上报数据
input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state);
input_sync(data->input_dev_ps);
printk("%s: report ABS_DISTANCE=%s ",__func__, data->ps_state ? "far" : "near");
ps_state_last = data->ps_state; //Report ABS value only if the state changed.
}
else
printk("%s: ps_state still %s ", __func__, data->ps_state ? "far" : "near");
}
workout:
enable_irq(data->irq); //使能 irq
mutex_unlock(&data->op_lock); //解锁
}