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

📄 irq.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * SMP flags value to restore to: * 0 - global cli * 1 - global sti * 2 - local cli * 3 - local sti */unsigned long __global_save_flags(void){	int retval;	int local_enabled;	unsigned long flags;	int cpu = smp_processor_id();	__save_flags(flags);#ifdef CONFIG_IA64	local_enabled = (flags & IA64_PSR_I) != 0;#else	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;#endif	/* default to local */	retval = 2 + local_enabled;	/* check for global flags if we're not in an interrupt */	if (!really_local_irq_count()) {		if (local_enabled)			retval = 1;		if (global_irq_holder == cpu)			retval = 0;	}	return retval;}void __global_restore_flags(unsigned long flags){	switch (flags) {	case 0:		__global_cli();		break;	case 1:		__global_sti();		break;	case 2:		__cli();		break;	case 3:		__sti();		break;	default:		printk("global_restore_flags: %08lx (%08lx)\n",			flags, (&flags)[-1]);	}}#endif/* * This should really return information about whether * we should do bottom half handling etc. Right now we * end up _always_ checking the bottom half, which is a * waste of time and is not what some drivers would * prefer. */int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action){	int status;	local_irq_enter(irq);	status = 1;	/* Force the "do bottom halves" bit */	if (!(action->flags & SA_INTERRUPT))		__sti();	do {		status |= action->flags;		action->handler(irq, action->dev_id, regs);		action = action->next;	} while (action);	if (status & SA_SAMPLE_RANDOM)		add_interrupt_randomness(irq);	__cli();	local_irq_exit(irq);	return status;}/** *	disable_irq_nosync - disable an irq without waiting *	@irq: Interrupt to disable * *	Disable the selected interrupt line.  Disables and Enables are *	nested. *	Unlike disable_irq(), this function does not ensure existing *	instances of the IRQ handler have completed before returning. * *	This function may be called from IRQ context. */inline void disable_irq_nosync(unsigned int irq){	irq_desc_t *desc = irq_desc(irq);	unsigned long flags;	spin_lock_irqsave(&desc->lock, flags);	if (!desc->depth++) {		desc->status |= IRQ_DISABLED;		desc->handler->disable(irq);	}	spin_unlock_irqrestore(&desc->lock, flags);}/** *	disable_irq - disable an irq and wait for completion *	@irq: Interrupt to disable * *	Disable the selected interrupt line.  Enables and Disables are *	nested. *	This function waits for any pending IRQ handlers for this interrupt *	to complete before returning. If you use this function while *	holding a resource the IRQ handler may need you will deadlock. * *	This function may be called - with care - from IRQ context. */void disable_irq(unsigned int irq){	disable_irq_nosync(irq);#ifdef CONFIG_SMP	if (!really_local_irq_count()) {		do {			barrier();		} while (irq_desc(irq)->status & IRQ_INPROGRESS);	}#endif}/** *	enable_irq - enable handling of an irq *	@irq: Interrupt to enable * *	Undoes the effect of one call to disable_irq().  If this *	matches the last disable, processing of interrupts on this *	IRQ line is re-enabled. * *	This function may be called from IRQ context. */void enable_irq(unsigned int irq){	irq_desc_t *desc = irq_desc(irq);	unsigned long flags;	spin_lock_irqsave(&desc->lock, flags);	switch (desc->depth) {	case 1: {		unsigned int status = desc->status & ~IRQ_DISABLED;		desc->status = status;		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {			desc->status = status | IRQ_REPLAY;			hw_resend_irq(desc->handler,irq);		}		desc->handler->enable(irq);		/* fall-through */	}	default:		desc->depth--;		break;	case 0:		printk("enable_irq(%u) unbalanced from %p\n",		       irq, (void *) __builtin_return_address(0));	}	spin_unlock_irqrestore(&desc->lock, flags);}/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */unsigned int do_IRQ(unsigned long 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;	kstat.irqs[cpu][irq]++;	if (desc->status & IRQ_PER_CPU) {		/* no locking required for CPU-local interrupts: */		desc->handler->ack(irq);		handle_IRQ_event(irq, regs, desc->action);		desc->handler->end(irq);	} else {		spin_lock(&desc->lock);		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 do_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))				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);	}	return 1;}/** *	request_irq - allocate an interrupt line *	@irq: Interrupt line to allocate *	@handler: Function to be called when the IRQ occurs *	@irqflags: Interrupt type flags *	@devname: An ascii name for the claiming device *	@dev_id: A cookie passed back to the handler function * *	This call allocates interrupt resources and enables the *	interrupt line and IRQ handling. From the point this *	call is made your handler function may be invoked. Since *	your handler function must clear any interrupt the board  *	raises, you must take care both to initialise your hardware *	and to set up the interrupt handler in the right order. * *	Dev_id must be globally unique. Normally the address of the *	device data structure is used as the cookie. Since the handler *	receives this value it makes sense to use it. * *	If your interrupt is shared you must pass a non NULL dev_id *	as this is required when freeing the interrupt. * *	Flags: * *	SA_SHIRQ		Interrupt is shared * *	SA_INTERRUPT		Disable local interrupts while processing * *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy * */int request_irq(unsigned int irq,		void (*handler)(int, void *, struct pt_regs *),		unsigned long irqflags,		const char * devname,		void *dev_id){	int retval;	struct irqaction * action;#if 1	/*	 * Sanity-check: shared interrupts should REALLY pass in	 * a real dev-ID, otherwise we'll have trouble later trying	 * to figure out which interrupt is which (messes up the	 * interrupt freeing logic etc).	 */	if (irqflags & SA_SHIRQ) {		if (!dev_id)			printk("Bad boy: %s called us without a dev_id!\n", devname);	}#endif	if (irq >= NR_IRQS)		return -EINVAL;	if (!handler)		return -EINVAL;	action = (struct irqaction *)			kmalloc(sizeof(struct irqaction), GFP_KERNEL);	if (!action)		return -ENOMEM;	action->handler = handler;	action->flags = irqflags;	action->mask = 0;	action->name = devname;	action->next = NULL;	action->dev_id = dev_id;	retval = setup_irq(irq, action);	if (retval)		kfree(action);	return retval;}/** *	free_irq - free an interrupt *	@irq: Interrupt line to free *	@dev_id: Device identity to free * *	Remove an interrupt handler. The handler is removed and if the *	interrupt line is no longer in use by any driver it is disabled. *	On a shared IRQ the caller must ensure the interrupt is disabled *	on the card it drives before calling this function. The function *	does not return until any executing interrupts for this IRQ *	have completed. * *	This function may be called from interrupt context.  * *	Bugs: Attempting to free an irq in a handler for the same irq hangs *	      the machine. */void free_irq(unsigned int irq, void *dev_id){	irq_desc_t *desc;	struct irqaction **p;	unsigned long flags;	if (irq >= NR_IRQS)		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 it - 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("Trying to free free IRQ%d\n",irq);		spin_unlock_irqrestore(&desc->lock,flags);		return;	}}/* * 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. */static DECLARE_MUTEX(probe_sem);/** *	probe_irq_on	- begin an interrupt autodetect * *	Commence probing for an interrupt. The interrupts are scanned

⌨️ 快捷键说明

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