中断API之setup_irq【转】
转自:https://blog.csdn.net/tiantao2012/article/details/78957472
- 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/78957472
- [html] view plain copy
- int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.
- 其使用的例程如下:
- struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
- {
- struct irq_domain *domain;
- insert_resource(&ioport_resource, &pic1_io_resource);
- insert_resource(&ioport_resource, &pic2_io_resource);
- init_8259A();
- domain = irq_domain_add_legacy(node, , I8259A_IRQ_BASE, ,
- &i8259A_ops, NULL);
- if (!domain)
- panic("Failed to add i8259 IRQ domain");
- setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
- return domain;
- }
- 其源码分析如下:
- int setup_irq(unsigned int irq, struct irqaction *act)
- {
- int retval;
- struct irq_desc *desc = irq_to_desc(irq);
- #中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出
- if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
- return -EINVAL;
- retval = irq_chip_pm_get(&desc->irq_data);
- if (retval < )
- return retval;
- #核心代码,设置irq对应的irqaction *act
- retval = __setup_irq(irq, desc, act);
- if (retval)
- irq_chip_pm_put(&desc->irq_data);
- return retval;
- }
- static int
- __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
- {
- struct irqaction *old, **old_ptr;
- unsigned long flags, thread_mask = ;
- int ret, nested, shared = ;
- #中断描述符为null,则退出
- if (!desc)
- return -EINVAL;
- #没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.
- if (desc->irq_data.chip == &no_irq_chip)
- return -ENOSYS;
- #增加这个模块的引用计数
- if (!try_module_get(desc->owner))
- return -ENODEV;
- #更新struct irqaction *new 中的irq number
- new->irq = irq;
- /*
- * If the trigger type is not specified by the caller,
- * then use the default for this interrupt.
- */
- #没有设置中断触发类型的话,则用默认值.
- if (!(new->flags & IRQF_TRIGGER_MASK))
- new->flags |= irqd_get_trigger_type(&desc->irq_data);
- /*
- * Check whether the interrupt nests into another interrupt
- * thread.
- */
- #检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套
- nested = irq_settings_is_nested_thread(desc);
- if (nested) {
- if (!new->thread_fn) {
- ret = -EINVAL;
- goto out_mput;
- }
- /*
- * Replace the primary handler which was provided from
- * the driver for non nested interrupt handling by the
- * dummy function which warns when called.
- */
- new->handler = irq_nested_primary_handler;
- } else {
- #这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化
- if (irq_settings_can_thread(desc)) {
- ret = irq_setup_forced_threading(new);
- if (ret)
- goto out_mput;
- }
- }
- /*
- * Create a handler thread when a thread function is supplied
- * and the interrupt does not nest into another interrupt
- * thread.
- */
- #在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程
- if (new->thread_fn && !nested) {
- ret = setup_irq_thread(new, irq, false);
- if (ret)
- goto out_mput;
- #中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.
- if (new->secondary) {
- ret = setup_irq_thread(new->secondary, irq, true);
- if (ret)
- goto out_thread;
- }
- }
- /*
- * Drivers are often written to work w/o knowledge about the
- * underlying irq chip implementation, so a request for a
- * threaded irq without a primary hard irq context handler
- * requires the ONESHOT flag to be set. Some irq chips like
- * MSI based interrupts are per se one shot safe. Check the
- * chip flags, so we can avoid the unmask dance at the end of
- * the threaded handler for those.
- */
- #有设置oneshot 标志的话,则清掉这个标志.
- if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
- new->flags &= ~IRQF_ONESHOT;
- /*
- * Protects against a concurrent __free_irq() call which might wait
- * for synchronize_irq() to complete without holding the optional
- * chip bus lock and desc->lock.
- */
- mutex_lock(&desc->request_mutex);
- /*
- * Acquire bus lock as the irq_request_resources() callback below
- * might rely on the serialization or the magic power management
- * functions which are abusing the irq_bus_lock() callback,
- */
- chip_bus_lock(desc);
- /* First installed action requests resources. */
- #中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.
- if (!desc->action) {
- ret = irq_request_resources(desc);
- if (ret) {
- pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
- new->name, irq, desc->irq_data.chip->name);
- goto out_bus_unlock;
- }
- }
- /*
- * The following block of code has to be executed atomically
- * protected against a concurrent interrupt and any of the other
- * management calls which are not serialized via
- * desc->request_mutex or the optional bus lock.
- */
- raw_spin_lock_irqsave(&desc->lock, flags);
- old_ptr = &desc->action;
- old = *old_ptr;
- #如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了
- #这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.
- if (old) {
- /*
- * Can't share interrupts unless both agree to and are
- * the same type (level, edge, polarity). So both flag
- * fields must have IRQF_SHARED set and the bits which
- * set the trigger type must match. Also all must
- * agree on ONESHOT.
- */
- unsigned int oldtype;
- /*
- * If nobody did set the configuration before, inherit
- * the one provided by the requester.
- */
- if (irqd_trigger_type_was_set(&desc->irq_data)) {
- oldtype = irqd_get_trigger_type(&desc->irq_data);
- } else {
- oldtype = new->flags & IRQF_TRIGGER_MASK;
- irqd_set_trigger_type(&desc->irq_data, oldtype);
- }
- if (!((old->flags & new->flags) & IRQF_SHARED) ||
- (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
- ((old->flags ^ new->flags) & IRQF_ONESHOT))
- goto mismatch;
- /* All handlers must agree on per-cpuness */
- if ((old->flags & IRQF_PERCPU) !=
- (new->flags & IRQF_PERCPU))
- goto mismatch;
- /* add new interrupt at end of irq queue */
- do {
- /*
- * Or all existing action->thread_mask bits,
- * so we can find the next zero bit for this
- * new action.
- */
- thread_mask |= old->thread_mask;
- old_ptr = &old->next;
- old = *old_ptr;
- } while (old);
- shared = ;
- }
- /*
- * Setup the thread mask for this irqaction for ONESHOT. For
- * !ONESHOT irqs the thread mask is 0 so we can avoid a
- * conditional in irq_wake_thread().
- */
- if (new->flags & IRQF_ONESHOT) {
- /*
- * Unlikely to have 32 resp 64 irqs sharing one line,
- * but who knows.
- */
- if (thread_mask == ~0UL) {
- ret = -EBUSY;
- goto out_unlock;
- }
- /*
- * The thread_mask for the action is or'ed to
- * desc->thread_active to indicate that the
- * IRQF_ONESHOT thread handler has been woken, but not
- * yet finished. The bit is cleared when a thread
- * completes. When all threads of a shared interrupt
- * line have completed desc->threads_active becomes
- * zero and the interrupt line is unmasked. See
- * handle.c:irq_wake_thread() for further information.
- *
- * If no thread is woken by primary (hard irq context)
- * interrupt handlers, then desc->threads_active is
- * also checked for zero to unmask the irq line in the
- * affected hard irq flow handlers
- * (handle_[fasteoi|level]_irq).
- *
- * The new action gets the first zero bit of
- * thread_mask assigned. See the loop above which or's
- * all existing action->thread_mask bits.
- */
- new->thread_mask = 1UL << ffz(thread_mask);
- } else if (new->handler == irq_default_primary_handler &&
- !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
- /*
- * The interrupt was requested with handler = NULL, so
- * we use the default primary handler for it. But it
- * does not have the oneshot flag set. In combination
- * with level interrupts this is deadly, because the
- * default primary handler just wakes the thread, then
- * the irq lines is reenabled, but the device still
- * has the level irq asserted. Rinse and repeat....
- *
- * While this works for edge type interrupts, we play
- * it safe and reject unconditionally because we can't
- * say for sure which type this interrupt really
- * has. The type flags are unreliable as the
- * underlying chip implementation can override them.
- */
- pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
- irq);
- ret = -EINVAL;
- goto out_unlock;
- }
- #非共享中断
- if (!shared) {
- #初始化一个等待队列,这个等待队列包含在中断描述符中
- init_waitqueue_head(&desc->wait_for_threads);
- /* Setup the type (level, edge polarity) if configured: */
- if (new->flags & IRQF_TRIGGER_MASK) {
- ret = __irq_set_trigger(desc,
- new->flags & IRQF_TRIGGER_MASK);
- if (ret)
- goto out_unlock;
- }
- /*
- * Activate the interrupt. That activation must happen
- * independently of IRQ_NOAUTOEN. request_irq() can fail
- * and the callers are supposed to handle
- * that. enable_irq() of an interrupt requested with
- * IRQ_NOAUTOEN is not supposed to fail. The activation
- * keeps it in shutdown mode, it merily associates
- * resources if necessary and if that's not possible it
- * fails. Interrupts which are in managed shutdown mode
- * will simply ignore that activation request.
- */
- #激活这个中断
- ret = irq_activate(desc);
- if (ret)
- goto out_unlock;
- desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
- IRQS_ONESHOT | IRQS_WAITING);
- irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
- #是不是percpu中断
- if (new->flags & IRQF_PERCPU) {
- irqd_set(&desc->irq_data, IRQD_PER_CPU);
- irq_settings_set_per_cpu(desc);
- }
- if (new->flags & IRQF_ONESHOT)
- desc->istate |= IRQS_ONESHOT;
- /* Exclude IRQ from balancing if requested */
- #不用设置irq balance
- if (new->flags & IRQF_NOBALANCING) {
- irq_settings_set_no_balancing(desc);
- irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
- }
- #开始中断
- if (irq_settings_can_autoenable(desc)) {
- irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
- } else {
- /*
- * Shared interrupts do not go well with disabling
- * auto enable. The sharing interrupt might request
- * it while it's still disabled and then wait for
- * interrupts forever.
- */
- WARN_ON_ONCE(new->flags & IRQF_SHARED);
- /* Undo nested disables: */
- desc->depth = ;
- }
- } else if (new->flags & IRQF_TRIGGER_MASK) {
- unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
- unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);
- if (nmsk != omsk)
- /* hope the handler works with current trigger mode */
- pr_warn("irq %d uses trigger mode %u; requested %u\n",
- irq, omsk, nmsk);
- }
- *old_ptr = new;
- #设置power相关
- irq_pm_install_action(desc, new);
- /* Reset broken irq detection when installing new handler */
- desc->irq_count = ;
- desc->irqs_unhandled = ;
- /*
- * Check whether we disabled the irq via the spurious handler
- * before. Reenable it and give it another chance.
- */
- if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
- desc->istate &= ~IRQS_SPURIOUS_DISABLED;
- __enable_irq(desc);
- }
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- chip_bus_sync_unlock(desc);
- mutex_unlock(&desc->request_mutex);
- irq_setup_timings(desc, new);
- /*
- * Strictly no need to wake it up, but hung_task complains
- * when no hard interrupt wakes the thread up.
- */
- # 如果有中断线程的话,则wakeup线程
- if (new->thread)
- wake_up_process(new->thread);
- if (new->secondary)
- wake_up_process(new->secondary->thread);
- #注册irq在proc中的接口
- register_irq_proc(irq, desc);
- new->dir = NULL;
- register_handler_proc(irq, new);
- return ;
- mismatch:
- if (!(new->flags & IRQF_PROBE_SHARED)) {
- pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
- irq, new->flags, new->name, old->flags, old->name);
- #ifdef CONFIG_DEBUG_SHIRQ
- dump_stack();
- #endif
- }
- ret = -EBUSY;
- #一下都是异常case
- out_unlock:
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- if (!desc->action)
- irq_release_resources(desc);
- out_bus_unlock:
- chip_bus_sync_unlock(desc);
- mutex_unlock(&desc->request_mutex);
- out_thread:
- if (new->thread) {
- struct task_struct *t = new->thread;
- new->thread = NULL;
- kthread_stop(t);
- put_task_struct(t);
- }
- if (new->secondary && new->secondary->thread) {
- struct task_struct *t = new->secondary->thread;
- new->secondary->thread = NULL;
- kthread_stop(t);
- put_task_struct(t);
- }
- out_mput:
- module_put(desc->owner);
- return ret;
- }
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/78957472
- int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.
- 其使用的例程如下:
- struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
- {
- struct irq_domain *domain;
- insert_resource(&ioport_resource, &pic1_io_resource);
- insert_resource(&ioport_resource, &pic2_io_resource);
- init_8259A(0);
- domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,
- &i8259A_ops, NULL);
- if (!domain)
- panic("Failed to add i8259 IRQ domain");
- setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
- return domain;
- }
- 其源码分析如下:
- int setup_irq(unsigned int irq, struct irqaction *act)
- {
- int retval;
- struct irq_desc *desc = irq_to_desc(irq);
- #中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出
- if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
- return -EINVAL;
- retval = irq_chip_pm_get(&desc->irq_data);
- if (retval < 0)
- return retval;
- #核心代码,设置irq对应的irqaction *act
- retval = __setup_irq(irq, desc, act);
- if (retval)
- irq_chip_pm_put(&desc->irq_data);
- return retval;
- }
- static int
- __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
- {
- struct irqaction *old, **old_ptr;
- unsigned long flags, thread_mask = 0;
- int ret, nested, shared = 0;
- #中断描述符为null,则退出
- if (!desc)
- return -EINVAL;
- #没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.
- if (desc->irq_data.chip == &no_irq_chip)
- return -ENOSYS;
- #增加这个模块的引用计数
- if (!try_module_get(desc->owner))
- return -ENODEV;
- #更新struct irqaction *new 中的irq number
- new->irq = irq;
- /*
- * If the trigger type is not specified by the caller,
- * then use the default for this interrupt.
- */
- #没有设置中断触发类型的话,则用默认值.
- if (!(new->flags & IRQF_TRIGGER_MASK))
- new->flags |= irqd_get_trigger_type(&desc->irq_data);
- /*
- * Check whether the interrupt nests into another interrupt
- * thread.
- */
- #检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套
- nested = irq_settings_is_nested_thread(desc);
- if (nested) {
- if (!new->thread_fn) {
- ret = -EINVAL;
- goto out_mput;
- }
- /*
- * Replace the primary handler which was provided from
- * the driver for non nested interrupt handling by the
- * dummy function which warns when called.
- */
- new->handler = irq_nested_primary_handler;
- } else {
- #这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化
- if (irq_settings_can_thread(desc)) {
- ret = irq_setup_forced_threading(new);
- if (ret)
- goto out_mput;
- }
- }
- /*
- * Create a handler thread when a thread function is supplied
- * and the interrupt does not nest into another interrupt
- * thread.
- */
- #在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程
- if (new->thread_fn && !nested) {
- ret = setup_irq_thread(new, irq, false);
- if (ret)
- goto out_mput;
- #中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.
- if (new->secondary) {
- ret = setup_irq_thread(new->secondary, irq, true);
- if (ret)
- goto out_thread;
- }
- }
- /*
- * Drivers are often written to work w/o knowledge about the
- * underlying irq chip implementation, so a request for a
- * threaded irq without a primary hard irq context handler
- * requires the ONESHOT flag to be set. Some irq chips like
- * MSI based interrupts are per se one shot safe. Check the
- * chip flags, so we can avoid the unmask dance at the end of
- * the threaded handler for those.
- */
- #有设置oneshot 标志的话,则清掉这个标志.
- if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
- new->flags &= ~IRQF_ONESHOT;
- /*
- * Protects against a concurrent __free_irq() call which might wait
- * for synchronize_irq() to complete without holding the optional
- * chip bus lock and desc->lock.
- */
- mutex_lock(&desc->request_mutex);
- /*
- * Acquire bus lock as the irq_request_resources() callback below
- * might rely on the serialization or the magic power management
- * functions which are abusing the irq_bus_lock() callback,
- */
- chip_bus_lock(desc);
- /* First installed action requests resources. */
- #中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.
- if (!desc->action) {
- ret = irq_request_resources(desc);
- if (ret) {
- pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
- new->name, irq, desc->irq_data.chip->name);
- goto out_bus_unlock;
- }
- }
- /*
- * The following block of code has to be executed atomically
- * protected against a concurrent interrupt and any of the other
- * management calls which are not serialized via
- * desc->request_mutex or the optional bus lock.
- */
- raw_spin_lock_irqsave(&desc->lock, flags);
- old_ptr = &desc->action;
- old = *old_ptr;
- #如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了
- #这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.
- if (old) {
- /*
- * Can't share interrupts unless both agree to and are
- * the same type (level, edge, polarity). So both flag
- * fields must have IRQF_SHARED set and the bits which
- * set the trigger type must match. Also all must
- * agree on ONESHOT.
- */
- unsigned int oldtype;
- /*
- * If nobody did set the configuration before, inherit
- * the one provided by the requester.
- */
- if (irqd_trigger_type_was_set(&desc->irq_data)) {
- oldtype = irqd_get_trigger_type(&desc->irq_data);
- } else {
- oldtype = new->flags & IRQF_TRIGGER_MASK;
- irqd_set_trigger_type(&desc->irq_data, oldtype);
- }
- if (!((old->flags & new->flags) & IRQF_SHARED) ||
- (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
- ((old->flags ^ new->flags) & IRQF_ONESHOT))
- goto mismatch;
- /* All handlers must agree on per-cpuness */
- if ((old->flags & IRQF_PERCPU) !=
- (new->flags & IRQF_PERCPU))
- goto mismatch;
- /* add new interrupt at end of irq queue */
- do {
- /*
- * Or all existing action->thread_mask bits,
- * so we can find the next zero bit for this
- * new action.
- */
- thread_mask |= old->thread_mask;
- old_ptr = &old->next;
- old = *old_ptr;
- } while (old);
- shared = 1;
- }
- /*
- * Setup the thread mask for this irqaction for ONESHOT. For
- * !ONESHOT irqs the thread mask is 0 so we can avoid a
- * conditional in irq_wake_thread().
- */
- if (new->flags & IRQF_ONESHOT) {
- /*
- * Unlikely to have 32 resp 64 irqs sharing one line,
- * but who knows.
- */
- if (thread_mask == ~0UL) {
- ret = -EBUSY;
- goto out_unlock;
- }
- /*
- * The thread_mask for the action is or'ed to
- * desc->thread_active to indicate that the
- * IRQF_ONESHOT thread handler has been woken, but not
- * yet finished. The bit is cleared when a thread
- * completes. When all threads of a shared interrupt
- * line have completed desc->threads_active becomes
- * zero and the interrupt line is unmasked. See
- * handle.c:irq_wake_thread() for further information.
- *
- * If no thread is woken by primary (hard irq context)
- * interrupt handlers, then desc->threads_active is
- * also checked for zero to unmask the irq line in the
- * affected hard irq flow handlers
- * (handle_[fasteoi|level]_irq).
- *
- * The new action gets the first zero bit of
- * thread_mask assigned. See the loop above which or's
- * all existing action->thread_mask bits.
- */
- new->thread_mask = 1UL << ffz(thread_mask);
- } else if (new->handler == irq_default_primary_handler &&
- !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
- /*
- * The interrupt was requested with handler = NULL, so
- * we use the default primary handler for it. But it
- * does not have the oneshot flag set. In combination
- * with level interrupts this is deadly, because the
- * default primary handler just wakes the thread, then
- * the irq lines is reenabled, but the device still
- * has the level irq asserted. Rinse and repeat....
- *
- * While this works for edge type interrupts, we play
- * it safe and reject unconditionally because we can't
- * say for sure which type this interrupt really
- * has. The type flags are unreliable as the
- * underlying chip implementation can override them.
- */
- pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
- irq);
- ret = -EINVAL;
- goto out_unlock;
- }
- #非共享中断
- if (!shared) {
- #初始化一个等待队列,这个等待队列包含在中断描述符中
- init_waitqueue_head(&desc->wait_for_threads);
- /* Setup the type (level, edge polarity) if configured: */
- if (new->flags & IRQF_TRIGGER_MASK) {
- ret = __irq_set_trigger(desc,
- new->flags & IRQF_TRIGGER_MASK);
- if (ret)
- goto out_unlock;
- }
- /*
- * Activate the interrupt. That activation must happen
- * independently of IRQ_NOAUTOEN. request_irq() can fail
- * and the callers are supposed to handle
- * that. enable_irq() of an interrupt requested with
- * IRQ_NOAUTOEN is not supposed to fail. The activation
- * keeps it in shutdown mode, it merily associates
- * resources if necessary and if that's not possible it
- * fails. Interrupts which are in managed shutdown mode
- * will simply ignore that activation request.
- */
- #激活这个中断
- ret = irq_activate(desc);
- if (ret)
- goto out_unlock;
- desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
- IRQS_ONESHOT | IRQS_WAITING);
- irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
- #是不是percpu中断
- if (new->flags & IRQF_PERCPU) {
- irqd_set(&desc->irq_data, IRQD_PER_CPU);
- irq_settings_set_per_cpu(desc);
- }
- if (new->flags & IRQF_ONESHOT)
- desc->istate |= IRQS_ONESHOT;
- /* Exclude IRQ from balancing if requested */
- #不用设置irq balance
- if (new->flags & IRQF_NOBALANCING) {
- irq_settings_set_no_balancing(desc);
- irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
- }
- #开始中断
- if (irq_settings_can_autoenable(desc)) {
- irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
- } else {
- /*
- * Shared interrupts do not go well with disabling
- * auto enable. The sharing interrupt might request
- * it while it's still disabled and then wait for
- * interrupts forever.
- */
- WARN_ON_ONCE(new->flags & IRQF_SHARED);
- /* Undo nested disables: */
- desc->depth = 1;
- }
- } else if (new->flags & IRQF_TRIGGER_MASK) {
- unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
- unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);
- if (nmsk != omsk)
- /* hope the handler works with current trigger mode */
- pr_warn("irq %d uses trigger mode %u; requested %u\n",
- irq, omsk, nmsk);
- }
- *old_ptr = new;
- #设置power相关
- irq_pm_install_action(desc, new);
- /* Reset broken irq detection when installing new handler */
- desc->irq_count = 0;
- desc->irqs_unhandled = 0;
- /*
- * Check whether we disabled the irq via the spurious handler
- * before. Reenable it and give it another chance.
- */
- if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
- desc->istate &= ~IRQS_SPURIOUS_DISABLED;
- __enable_irq(desc);
- }
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- chip_bus_sync_unlock(desc);
- mutex_unlock(&desc->request_mutex);
- irq_setup_timings(desc, new);
- /*
- * Strictly no need to wake it up, but hung_task complains
- * when no hard interrupt wakes the thread up.
- */
- # 如果有中断线程的话,则wakeup线程
- if (new->thread)
- wake_up_process(new->thread);
- if (new->secondary)
- wake_up_process(new->secondary->thread);
- #注册irq在proc中的接口
- register_irq_proc(irq, desc);
- new->dir = NULL;
- register_handler_proc(irq, new);
- return 0;
- mismatch:
- if (!(new->flags & IRQF_PROBE_SHARED)) {
- pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
- irq, new->flags, new->name, old->flags, old->name);
- #ifdef CONFIG_DEBUG_SHIRQ
- dump_stack();
- #endif
- }
- ret = -EBUSY;
- #一下都是异常case
- out_unlock:
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- if (!desc->action)
- irq_release_resources(desc);
- out_bus_unlock:
- chip_bus_sync_unlock(desc);
- mutex_unlock(&desc->request_mutex);
- out_thread:
- if (new->thread) {
- struct task_struct *t = new->thread;
- new->thread = NULL;
- kthread_stop(t);
- put_task_struct(t);
- }
- if (new->secondary && new->secondary->thread) {
- struct task_struct *t = new->secondary->thread;
- new->secondary->thread = NULL;
- kthread_stop(t);
- put_task_struct(t);
- }
- out_mput:
- module_put(desc->owner);
- return ret;
- }
中断API之setup_irq【转】的更多相关文章
- Linux kernel的中断子系统之(五):驱动申请中断API
返回目录:<ARM-Linux中断系统>. 总结:二重点区分了抢占式内核和非抢占式内核的区别:抢占式内核可以在内核空间进行抢占,通过对中断处理进行线程化可以提高Linux内核实时性. 三介 ...
- Linux中断 - 驱动申请中断API
一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的驱动的时候,如何向Linux Kernel中的中断子系统注册中断处理函数?为了理解注册中断的接口,必须了解一些中断线程化(threa ...
- Linux kernel中断子系统之(五):驱动申请中断API【转】
转自:http://www.wowotech.net/linux_kenrel/request_threaded_irq.html 一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的 ...
- GPIO口及中断API函数【转】
本文转载自:http://blog.sina.com.cn/s/blog_a6559d9201015vx9.htmlG #include <linux/gpio.h> // 标准 GPIO ...
- 中断API之enable_irq
void enable_irq(unsigned int irq) 用于使能一个irq. void disable_irq(unsigned int irq)则用于禁止一个irq 其使用的例程如下: ...
- 非常好!!!Linux源代码阅读——中断【转】
Linux源代码阅读——中断 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/2_int.html 目录 为什么要有中断 中断的作用 中断的处 ...
- Intel 80x86 Linux Kernel Interrupt(中断)、Interrupt Priority、Interrupt nesting、Prohibit Things Whthin CPU In The Interrupt Off State
目录 . 引言 . Linux 中断的概念 . 中断处理流程 . Linux 中断相关的源代码分析 . Linux 硬件中断 . Linux 软中断 . 中断优先级 . CPU在关中断状态下编程要注意 ...
- 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)
作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的 ...
- ARM-Linux中断系统
1.前言 了解Linux中断子系统,同时也需要了解ARM体系结构中断处理流程:在熟悉整个软硬件架构和流程基础上,才能对流程进行细化,然后找出问题的瓶颈.<2. 梳理中断处理子系统> 但是所 ...
随机推荐
- NetFPGA-1G-CML从零开始环境配置
NetFPGA-1G-CML从零开始环境配置 前言 偶得一块NetFPGA-1G-CML,跟着github对NetFPGA-1G-CML的入门指南,一步步把配置环境终于搭建起来,下面重新复现一下此过程 ...
- eclipse maven项目目录
今天遇见一个错误,关于eclipse项目的路径问题,web-inf的路径,上图和下图出现了两种web-INF,src的web-INFf和webContent的web-INF,src里面的文件需要编译以 ...
- python全栈开发-json和pickle模块(数据的序列化)
一.什么是序列化? 我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flat ...
- 用C#(.NET Core) 实现简单工厂和工厂方法模式
本文源自深入浅出设计模式. 只不过我是使用C#/.NET Core实现的例子. 前言 当你看见new这个关键字的时候, 就应该想到它是具体的实现. 这就是一个具体的类, 为了更灵活, 我们应该使用的是 ...
- Spring知识点回顾(08)spring aware
Spring知识点回顾(08)spring aware BeanNameAware 获得容器中的bean名称 BeanFactoryAware 获得当前的bean factory Applicatio ...
- c# 工具类(字符串和时间,文件)
using System; using System.IO; using System.Text.RegularExpressions; using System.Windows.Browser; n ...
- python中的turtle库绘制图形
1. 前奏: 在用turtle绘制图形时,需要安装对应python的解释器以及IDE,我安装的是pycharm,在安装完pycharm后,在pycharm安装相应库的模块,绘图可以引入turtle模块 ...
- Django实现发邮件
1 首先去自己的邮箱申请,在设置里面找,申请开通smtp服务,我用的是163邮箱 2 在项目下settings.py中添加设置: # 配置邮箱发邮件的相关功能 #这一项是固定的 EMAIL_BACKE ...
- JavaScript 重点笔记
JavaScript 重点笔记 ## 数组 // 必须掌握 - arr.length:获取数组元素的长度 - arr.splice(起始位置,长度):从数组中添加或删除元素. - arr.indexO ...
- Linux-centos-7.2-64bit 安装配置mysql
2018-04-12 安装在/usr/local/下,配置文件在/etc/my.ini 1.下载mysql安装包到 /usr/local/software cd /usr/local/software ...