⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irq.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
	action->next = NULL;	action->dev_id = dev_id;#ifdef CONFIG_SMP	select_smp_affinity(irq);#endif	retval = setup_irq(irq, action);	if (retval)		kfree(action);	return retval;}EXPORT_SYMBOL(request_irq);voidfree_irq(unsigned int irq, void *dev_id){	irq_desc_t *desc;	struct irqaction **p;	unsigned long flags;	if (irq >= ACTUAL_NR_IRQS) {		printk(KERN_CRIT "Trying to free IRQ%d\n", irq);		return;	}	desc = irq_desc + irq;	spin_lock_irqsave(&desc->lock,flags);	p = &desc->action;	for (;;) {		struct irqaction * action = *p;		if (action) {			struct irqaction **pp = p;			p = &action->next;			if (action->dev_id != dev_id)				continue;			/* Found - now remove it from the list of entries.  */			*pp = action->next;			if (!desc->action) {				desc->status |= IRQ_DISABLED;				desc->handler->shutdown(irq);			}			spin_unlock_irqrestore(&desc->lock,flags);#ifdef CONFIG_SMP			/* Wait to make sure it's not being used on			   another CPU.  */			while (desc->status & IRQ_INPROGRESS)				barrier();#endif			kfree(action);			return;		}		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);		spin_unlock_irqrestore(&desc->lock,flags);		return;	}}EXPORT_SYMBOL(free_irq);intshow_interrupts(struct seq_file *p, void *v){#ifdef CONFIG_SMP	int j;#endif	int i = *(loff_t *) v;	struct irqaction * action;	unsigned long flags;#ifdef CONFIG_SMP	if (i == 0) {		seq_puts(p, "           ");		for (i = 0; i < NR_CPUS; i++)			if (cpu_online(i))				seq_printf(p, "CPU%d       ", i);		seq_putc(p, '\n');	}#endif	if (i < ACTUAL_NR_IRQS) {		spin_lock_irqsave(&irq_desc[i].lock, flags);		action = irq_desc[i].action;		if (!action) 			goto unlock;		seq_printf(p, "%3d: ",i);#ifndef CONFIG_SMP		seq_printf(p, "%10u ", kstat_irqs(i));#else		for (j = 0; j < NR_CPUS; j++)			if (cpu_online(j))				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);#endif		seq_printf(p, " %14s", irq_desc[i].handler->typename);		seq_printf(p, "  %c%s",			(action->flags & SA_INTERRUPT)?'+':' ',			action->name);		for (action=action->next; action; action = action->next) {			seq_printf(p, ", %c%s",				  (action->flags & SA_INTERRUPT)?'+':' ',				   action->name);		}		seq_putc(p, '\n');unlock:		spin_unlock_irqrestore(&irq_desc[i].lock, flags);	} else if (i == ACTUAL_NR_IRQS) {#ifdef CONFIG_SMP		seq_puts(p, "IPI: ");		for (i = 0; i < NR_CPUS; i++)			if (cpu_online(i))				seq_printf(p, "%10lu ", cpu_data[i].ipi_count);		seq_putc(p, '\n');#endif		seq_printf(p, "ERR: %10lu\n", irq_err_count);	}	return 0;}/* * handle_irq handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */#define MAX_ILLEGAL_IRQS 16voidhandle_irq(int irq, struct pt_regs * regs){		/* 	 * We ack quickly, we don't want the irq controller	 * thinking we're snobs just because some other CPU has	 * disabled global interrupts (we have already done the	 * INT_ACK cycles, it's too late to try to pretend to the	 * controller that we aren't taking the interrupt).	 *	 * 0 return value means that this irq is already being	 * handled by some other CPU. (or is disabled)	 */	int cpu = smp_processor_id();	irq_desc_t *desc = irq_desc + irq;	struct irqaction * action;	unsigned int status;	static unsigned int illegal_count=0;		if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {		irq_err_count++;		illegal_count++;		printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",		       irq);		return;	}	irq_enter();	kstat_cpu(cpu).irqs[irq]++;	spin_lock_irq(&desc->lock); /* mask also the higher prio events */	desc->handler->ack(irq);	/*	 * REPLAY is when Linux resends an IRQ that was dropped earlier.	 * WAITING is used by probe to mark irqs that are being tested.	 */	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);	status |= IRQ_PENDING; /* we _want_ to handle it */	/*	 * If the IRQ is disabled for whatever reason, we cannot	 * use the action we have.	 */	action = NULL;	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		action = desc->action;		status &= ~IRQ_PENDING; /* we commit to handling */		status |= IRQ_INPROGRESS; /* we are handling it */	}	desc->status = status;	/*	 * If there is no IRQ handler or it was disabled, exit early.	 * Since we set PENDING, if another processor is handling	 * a different instance of this same irq, the other processor	 * will take care of it.	 */	if (!action)		goto out;	/*	 * Edge triggered interrupts need to remember pending events.	 * This applies to any hw interrupts that allow a second	 * instance of the same irq to arrive while we are in handle_irq	 * or in the handler. But the code here only handles the _second_	 * instance of the irq, not the third or fourth. So it is mostly	 * useful for irq hardware that does not mask cleanly in an	 * SMP environment.	 */	for (;;) {		spin_unlock(&desc->lock);		handle_IRQ_event(irq, regs, action);		spin_lock(&desc->lock);				if (!(desc->status & IRQ_PENDING)		    || (desc->status & IRQ_LEVEL))			break;		desc->status &= ~IRQ_PENDING;	}	desc->status &= ~IRQ_INPROGRESS;out:	/*	 * The ->end() handler has to deal with interrupts which got	 * disabled while the handler was running.	 */	desc->handler->end(irq);	spin_unlock(&desc->lock);	irq_exit();}/* * IRQ autodetection code.. * * This depends on the fact that any interrupt that * comes in on to an unassigned handler will get stuck * with "IRQ_WAITING" cleared and the interrupt * disabled. */unsigned longprobe_irq_on(void){	int i;	irq_desc_t *desc;	unsigned long delay;	unsigned long val;	/* Something may have generated an irq long ago and we want to	   flush such a longstanding irq before considering it as spurious. */	for (i = NR_IRQS-1; i >= 0; i--) {		desc = irq_desc + i;		spin_lock_irq(&desc->lock);		if (!irq_desc[i].action) 			irq_desc[i].handler->startup(i);		spin_unlock_irq(&desc->lock);	}	/* Wait for longstanding interrupts to trigger. */	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )		/* about 20ms delay */ barrier();	/* enable any unassigned irqs (we must startup again here because	   if a longstanding irq happened in the previous stage, it may have	   masked itself) first, enable any unassigned irqs. */	for (i = NR_IRQS-1; i >= 0; i--) {		desc = irq_desc + i;		spin_lock_irq(&desc->lock);		if (!desc->action) {			desc->status |= IRQ_AUTODETECT | IRQ_WAITING;			if (desc->handler->startup(i))				desc->status |= IRQ_PENDING;		}		spin_unlock_irq(&desc->lock);	}	/*	 * Wait for spurious interrupts to trigger	 */	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )		/* about 100ms delay */ barrier();	/*	 * Now filter out any obviously spurious interrupts	 */	val = 0;	for (i=0; i<NR_IRQS; i++) {		irq_desc_t *desc = irq_desc + i;		unsigned int status;		spin_lock_irq(&desc->lock);		status = desc->status;		if (status & IRQ_AUTODETECT) {			/* It triggered already - consider it spurious. */			if (!(status & IRQ_WAITING)) {				desc->status = status & ~IRQ_AUTODETECT;				desc->handler->shutdown(i);			} else				if (i < 32)					val |= 1 << i;		}		spin_unlock_irq(&desc->lock);	}	return val;}EXPORT_SYMBOL(probe_irq_on);/* * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). */unsigned intprobe_irq_mask(unsigned long val){	int i;	unsigned int mask;	mask = 0;	for (i = 0; i < NR_IRQS; i++) {		irq_desc_t *desc = irq_desc + i;		unsigned int status;		spin_lock_irq(&desc->lock);		status = desc->status;		if (status & IRQ_AUTODETECT) {			/* We only react to ISA interrupts */			if (!(status & IRQ_WAITING)) {				if (i < 16)					mask |= 1 << i;			}			desc->status = status & ~IRQ_AUTODETECT;			desc->handler->shutdown(i);		}		spin_unlock_irq(&desc->lock);	}	return mask & val;}/* * Get the result of the IRQ probe.. A negative result means that * we have several candidates (but we return the lowest-numbered * one). */intprobe_irq_off(unsigned long val){	int i, irq_found, nr_irqs;	nr_irqs = 0;	irq_found = 0;	for (i=0; i<NR_IRQS; i++) {		irq_desc_t *desc = irq_desc + i;		unsigned int status;		spin_lock_irq(&desc->lock);		status = desc->status;		if (status & IRQ_AUTODETECT) {			if (!(status & IRQ_WAITING)) {				if (!nr_irqs)					irq_found = i;				nr_irqs++;			}			desc->status = status & ~IRQ_AUTODETECT;			desc->handler->shutdown(i);		}		spin_unlock_irq(&desc->lock);	}	if (nr_irqs > 1)		irq_found = -irq_found;	return irq_found;}EXPORT_SYMBOL(probe_irq_off);#ifdef CONFIG_SMPvoid synchronize_irq(unsigned int irq){        /* is there anything to synchronize with? */	if (!irq_desc[irq].action)		return;	while (irq_desc[irq].status & IRQ_INPROGRESS)		barrier();}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -