1、上半部和下半部
由于中断随时可能发生,所以必须保证中断处理程序可以快速执行;但是中断处理程序可能又会处理大量的任务,两者之间存在矛盾,所以一般会把中断处理的过程分成两部分:上半部和下半部。
上半部也叫硬中断,是通常意义上的中断处理程序,用来接收中断,和简单的、有时限的处理工作,例如对中断接收后进行应答或者复位硬件等需要在所有中断被禁止的情况下完成的工作。而其他的允许稍后完成的工作,则会推迟到下半部在合适的时间完成。Linux有多种机制来实现下半部,其中一种就是软中断。 对于网卡的中断处理,上半部会执行 通知硬件、拷贝网络数据报到内存并继续读取新数据包,这些重要、紧急且与硬件相关的工作,因为网卡接收的网络数据包的缓存大小通常是固定的、有限的,一旦被延迟可能造成缓存溢出。而数据包的处理等操作,则由下半部来完成。
2、下半部主要用来处理一些比较耗时的操作,linux有很多中实现方式,包括tasklet、软中断、工作队列。即软中断是下半部的一种实现方式。
3、下面是以9x07平台为例实现gpio发生中断后,cpu通过iic去读sensor(smi230)数据,然后通过input子系统把数据上报
申请irq
err = smi230_request_irq(client_data);
if (err < 0) {
PERR("Request irq failed");
goto exit_cleanup_sysfs;
}
中断部分代码:
在smi230_new_data_ready_handle(client_data);中通过input上报数据
static void smi230_irq_work_func(struct work_struct *work)
{
#ifndef CONFIG_SMI230_DATA_SYNC
struct smi230_client_data *client_data =
container_of(work, struct smi230_client_data, irq_work);
#ifdef CONFIG_SMI230_GYRO_FIFO
smi230_gyro_fifo_handle(client_data);
#else
smi230_new_data_ready_handle(client_data);
#endif
#endif
}
static irqreturn_t smi230_irq_handle(int irq, void *handle)
{
struct smi230_client_data *client_data = handle;
int err = 0;
err = schedule_work(&client_data->irq_work);
if (err < 0)
PERR("schedule_work failedn");
return IRQ_HANDLED;
}
static void smi230_free_irq(struct smi230_client_data *client_data)
{
cancel_work_sync(&client_data->irq_work);
free_irq(client_data->IRQ, client_data);
gpio_free(client_data->gpio_pin);
}
static int smi230_request_irq(struct smi230_client_data *client_data)
{
int err = 0;
INIT_WORK(&client_data->irq_work, smi230_irq_work_func);
client_data->gpio_pin = 34;
PINFO("SMI230_GYRO gpio number:%dn", client_data->gpio_pin);
err = gpio_request_one(client_data->gpio_pin,
GPIOF_IN, "smi230_gyro_interrupt");
if (err < 0) {
PDEBUG("gpio_request_onen");
return err;
}
err = gpio_direction_input(client_data->gpio_pin);
if (err < 0) {
PDEBUG("gpio_direction_inputn");
return err;
}
client_data->IRQ = gpio_to_irq(client_data->gpio_pin);
err = request_irq(client_data->IRQ, smi230_irq_handle,
IRQF_TRIGGER_RISING,
SENSOR_GYRO_NAME, client_data);
if (err < 0) {
PDEBUG("request_irqn");
return err;
}
return err;
}
注册input设备
err = smi230_input_init(client_data);
if (err < 0) {
PERR("input init failed");
goto exit_free_client_data;
}
err = sysfs_create_group(&client_data->input->dev.kobj,
&smi230_attribute_group);
if (err < 0) {
PERR("sysfs create failed");
goto exit_cleanup_input;
}
smi230_input_init实现
static struct attribute *smi230_attributes[] = {
&dev_attr_chip_id.attr,
&dev_attr_regs_dump.attr,
&dev_attr_fifo_wm.attr,
&dev_attr_pwr_cfg.attr,
&dev_attr_bw_odr.attr,
&dev_attr_range.attr,
&dev_attr_gyro_value.attr,
&dev_attr_driver_version.attr,
NULL
};
static struct attribute_group smi230_attribute_group = {
.attrs = smi230_attributes
};
static int smi230_input_init(struct smi230_client_data *client_data)
{
int err = 0;
struct input_dev *dev = input_allocate_device();
if (dev == NULL)
return -ENOMEM;
dev->id.bustype = BUS_I2C;
dev->name = SENSOR_GYRO_NAME;
dev_set_name(&dev->dev, SENSOR_GYRO_NAME);
input_set_drvdata(dev, client_data);
client_data->input = dev;
input_set_capability(dev, EV_MSC, MSC_RAW);
input_set_capability(dev, EV_MSC, MSC_GESTURE);
input_set_abs_params(dev, ABS_X, SMI230_MIN_VALUE, SMI230_MAX_VALUE, 0, 0);
input_set_abs_params(dev, ABS_Y, SMI230_MIN_VALUE, SMI230_MAX_VALUE, 0, 0);
input_set_abs_params(dev, ABS_Z, SMI230_MIN_VALUE, SMI230_MAX_VALUE, 0, 0);
err = input_register_device(dev);
if (err)
input_free_device(dev);
return err;
}
数据上报,在中断中调用
static void smi230_new_data_ready_handle(
struct smi230_client_data *client_data)
{
struct smi230_sensor_data gyro_data;
int err = 0;
err = smi230_gyro_get_data(&gyro_data, p_smi230_dev); //通过iic读数据
if (err != SMI230_OK)
return;
input_event(client_data->input, EV_MSC, MSC_GESTURE, (int)gyro_data.x);
input_event(client_data->input, EV_MSC, MSC_GESTURE, (int)gyro_data.y);
input_event(client_data->input, EV_MSC, MSC_GESTURE, (int)gyro_data.z);
input_sync(client_data->input);
}



