*参照元 [#d48e68a8] #backlinks *説明 [#x4d90806] -パス: [[linux-2.6.33/kernel/irq/manage.c]] -FIXME: これは何? --説明 **引数 [#t4753fa3] -unsigned int irq -- -struct irq_desc *desc -- --[[linux-2.6.33/irq_desc]] -struct irqaction *new -- --[[linux-2.6.33/irqaction]] **返り値 [#m9d62e62] -int -- **参考 [#l4f13062] *実装 [#ab3fbc76] /* * Internal function to register an irqaction - typically used to * allocate special interrupts that are part of the architecture. */ static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) { struct irqaction *old, **old_ptr; - --[[linux-2.6.33/irqaction]] const char *old_name = NULL; unsigned long flags; int nested, shared = 0; int ret; if (!desc) return -EINVAL; if (desc->chip == &no_irq_chip) return -ENOSYS; /* * Some drivers like serial.c use request_irq() heavily, * so we have to be careful not to interfere with a * running system. */ if (new->flags & IRQF_SAMPLE_RANDOM) { /* * This function might sleep, we want to call it first, * outside of the atomic block. * Yes, this might clear the entropy pool if the wrong * driver is attempted to be loaded, without actually * installing a new handler, but is this really a problem, * only the sysadmin is able to do this. */ rand_initialize_irq(irq); } - --[[linux-2.6.33/rand_initalize_irq()]] /* Oneshot interrupts are not allowed with shared */ if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED)) return -EINVAL; /* * Check whether the interrupt nests into another interrupt * thread. */ nested = desc->status & IRQ_NESTED_THREAD; if (nested) { if (!new->thread_fn) return -EINVAL; /* * 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; } - --[[linux-2.6.33/irq_nested_primary_handler()]] /* * 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) { struct task_struct *t; t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name); if (IS_ERR(t)) return PTR_ERR(t); - --[[linux-2.6.33/task_struct]] --[[linux-2.6.33/kthread_create()]] --[[linux-2.6.33/IS_ERR()]] --[[linux-2.6.33/PTR_ERR()]] /* * We keep the reference to the task struct even if * the thread dies to avoid that the interrupt code * references an already freed task_struct. */ get_task_struct(t); new->thread = t; - --[[linux-2.6.33/get_task_struct()]] } /* * The following block of code has to be executed atomically */ raw_spin_lock_irqsave(&desc->lock, flags); - --[[linux-2.6.33/raw_spin_lock_irqsave()]] old_ptr = &desc->action; old = *old_ptr; 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. */ if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) { old_name = old->name; goto mismatch; } #if defined(CONFIG_IRQ_PER_CPU) /* All handlers must agree on per-cpuness */ if ((old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU)) goto mismatch; #endif /* add new interrupt at end of irq queue */ do { old_ptr = &old->next; old = *old_ptr; } while (old); shared = 1; } if (!shared) { irq_chip_set_defaults(desc->chip); - --[[linux-2.6.33/irq_chip_set_defaults()]] init_waitqueue_head(&desc->wait_for_threads); - --[[linux-2.6.33/init_waitqueue_head()]] /* Setup the type (level, edge polarity) if configured: */ if (new->flags & IRQF_TRIGGER_MASK) { ret = __irq_set_trigger(desc, irq, new->flags & IRQF_TRIGGER_MASK); if (ret) goto out_thread; - --[[linux-2.6.33/__irq_set_trigger()]] } else compat_irq_chip_set_default_handler(desc); - --[[linux-2.6.33/compat_irq_chip_set_default_handler()]] #if defined(CONFIG_IRQ_PER_CPU) if (new->flags & IRQF_PERCPU) desc->status |= IRQ_PER_CPU; #endif desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); if (new->flags & IRQF_ONESHOT) desc->status |= IRQ_ONESHOT; if (!(desc->status & IRQ_NOAUTOEN)) { desc->depth = 0; desc->status &= ~IRQ_DISABLED; desc->chip->startup(irq); } else /* Undo nested disables: */ desc->depth = 1; /* Exclude IRQ from balancing if requested */ if (new->flags & IRQF_NOBALANCING) desc->status |= IRQ_NO_BALANCING; /* Set default affinity mask once everything is setup */ setup_affinity(irq, desc); - --[[linux-2.6.33/setup_affinity()]] } else if ((new->flags & IRQF_TRIGGER_MASK) && (new->flags & IRQF_TRIGGER_MASK) != (desc->status & IRQ_TYPE_SENSE_MASK)) { /* hope the handler works with the actual trigger mode... */ pr_warning("IRQ %d uses trigger mode %d; requested %d\n", irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK), (int)(new->flags & IRQF_TRIGGER_MASK)); - --[[linux-2.6.33/pr_warning()]] } new->irq = irq; *old_ptr = 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->status & IRQ_SPURIOUS_DISABLED)) { desc->status &= ~IRQ_SPURIOUS_DISABLED; __enable_irq(desc, irq, false); } - --[[linux-2.6.33/__enable_irq()]] raw_spin_unlock_irqrestore(&desc->lock, flags); - --[[linux-2.6.33/raw_spin_unlock_irqrestore()]] /* * Strictly no need to wake it up, but hung_task complains * when no hard interrupt wakes the thread up. */ if (new->thread) wake_up_process(new->thread); - --[[linux-2.6.33/wake_up_process()]] register_irq_proc(irq, desc); - --[[linux-2.6.33/register_irq_proc()]] new->dir = NULL; register_handler_proc(irq, new); - --[[linux-2.6.33/register_handler_proc()]] return 0; mismatch: #ifdef CONFIG_DEBUG_SHIRQ if (!(new->flags & IRQF_PROBE_SHARED)) { printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq); if (old_name) printk(KERN_ERR "current handler: %s\n", old_name); dump_stack(); } - --[[linux-2.6.33/printk()]] --[[linux-2.6.33/dump_stack()]] #endif ret = -EBUSY; out_thread: raw_spin_unlock_irqrestore(&desc->lock, flags); - --[[linux-2.6.33/raw_spin_unlock_irqrestore()]] if (new->thread) { struct task_struct *t = new->thread; new->thread = NULL; if (likely(!test_bit(IRQTF_DIED, &new->thread_flags))) kthread_stop(t); - --[[linux-2.6.33/likely()]] --[[linux-2.6.33/test_bit()]] --[[linux-2.6.33/kthread_stop()]] put_task_struct(t); - --[[linux-2.6.33/put_task_struct()]] } return ret; } *コメント [#sd2b971b]