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

📄 irq.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (irq >= NR_IRQS)		desc = &bad_irq_desc;	irq_enter();	spin_lock(&irq_controller_lock);	desc_handle_irq(irq, desc, regs);	/*	 * Now re-run any pending interrupts.	 */	if (!list_empty(&irq_pending))		do_pending_irqs(regs);	irq_finish(irq);	spin_unlock(&irq_controller_lock);	irq_exit();}void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained){	struct irqdesc *desc;	unsigned long flags;	if (irq >= NR_IRQS) {		printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);		return;	}	if (handle == NULL)		handle = do_bad_IRQ;	desc = irq_desc + irq;	if (is_chained && desc->chip == &bad_chip)		printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);	spin_lock_irqsave(&irq_controller_lock, flags);	if (handle == do_bad_IRQ) {		desc->chip->mask(irq);		desc->chip->ack(irq);		desc->disable_depth = 1;	}	desc->handle = handle;	if (handle != do_bad_IRQ && is_chained) {		desc->valid = 0;		desc->probe_ok = 0;		desc->disable_depth = 0;		desc->chip->unmask(irq);	}	spin_unlock_irqrestore(&irq_controller_lock, flags);}void set_irq_chip(unsigned int irq, struct irqchip *chip){	struct irqdesc *desc;	unsigned long flags;	if (irq >= NR_IRQS) {		printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);		return;	}	if (chip == NULL)		chip = &bad_chip;	desc = irq_desc + irq;	spin_lock_irqsave(&irq_controller_lock, flags);	desc->chip = chip;	spin_unlock_irqrestore(&irq_controller_lock, flags);}int set_irq_type(unsigned int irq, unsigned int type){	struct irqdesc *desc;	unsigned long flags;	int ret = -ENXIO;	if (irq >= NR_IRQS) {		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);		return -ENODEV;	}	desc = irq_desc + irq;	if (desc->chip->set_type) {		spin_lock_irqsave(&irq_controller_lock, flags);		ret = desc->chip->set_type(irq, type);		spin_unlock_irqrestore(&irq_controller_lock, flags);	}	return ret;}EXPORT_SYMBOL(set_irq_type);void set_irq_flags(unsigned int irq, unsigned int iflags){	struct irqdesc *desc;	unsigned long flags;	if (irq >= NR_IRQS) {		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);		return;	}	desc = irq_desc + irq;	spin_lock_irqsave(&irq_controller_lock, flags);	desc->valid = (iflags & IRQF_VALID) != 0;	desc->probe_ok = (iflags & IRQF_PROBE) != 0;	desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;	spin_unlock_irqrestore(&irq_controller_lock, flags);}int setup_irq(unsigned int irq, struct irqaction *new){	int shared = 0;	struct irqaction *old, **p;	unsigned long flags;	struct irqdesc *desc;	/*	 * 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 & SA_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);	}	/*	 * The following block of code has to be executed atomically	 */	desc = irq_desc + irq;	spin_lock_irqsave(&irq_controller_lock, flags);	p = &desc->action;	if ((old = *p) != NULL) {		/* Can't share interrupts unless both agree to */		if (!(old->flags & new->flags & SA_SHIRQ)) {			spin_unlock_irqrestore(&irq_controller_lock, flags);			return -EBUSY;		}		/* add new interrupt at end of irq queue */		do {			p = &old->next;			old = *p;		} while (old);		shared = 1;	}	*p = new;	if (!shared) { 		desc->probing = 0;		desc->running = 0;		desc->pending = 0;		desc->disable_depth = 1;		if (!desc->noautoenable) {			desc->disable_depth = 0;			desc->chip->unmask(irq);		}	}	spin_unlock_irqrestore(&irq_controller_lock, flags);	return 0;}/** *	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, irqreturn_t (*handler)(int, void *, struct pt_regs *),		 unsigned long irq_flags, const char * devname, void *dev_id){	unsigned long retval;	struct irqaction *action;	if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||	    (irq_flags & SA_SHIRQ && !dev_id))		return -EINVAL;	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);	if (!action)		return -ENOMEM;	action->handler = handler;	action->flags = irq_flags;	cpus_clear(action->mask);	action->name = devname;	action->next = NULL;	action->dev_id = dev_id;	retval = setup_irq(irq, action);	if (retval)		kfree(action);	return retval;}EXPORT_SYMBOL(request_irq);/** *	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. * *	This function must not be called from interrupt context. */void free_irq(unsigned int irq, void *dev_id){	struct irqaction * action, **p;	unsigned long flags;	if (irq >= NR_IRQS || !irq_desc[irq].valid) {		printk(KERN_ERR "Trying to free IRQ%d\n",irq);		dump_stack();		return;	}	spin_lock_irqsave(&irq_controller_lock, flags);	for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {		if (action->dev_id != dev_id)			continue;	    	/* Found it - now free it */		*p = action->next;		break;	}	spin_unlock_irqrestore(&irq_controller_lock, flags);	if (!action) {		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);		dump_stack();	} else {		synchronize_irq(irq);		kfree(action);	}}EXPORT_SYMBOL(free_irq);static DECLARE_MUTEX(probe_sem);/* Start the interrupt probing.  Unlike other architectures, * we don't return a mask of interrupts from probe_irq_on, * but return the number of interrupts enabled for the probe. * The interrupts which have been enabled for probing is * instead recorded in the irq_desc structure. */unsigned long probe_irq_on(void){	unsigned int i, irqs = 0;	unsigned long delay;	down(&probe_sem);	/*	 * first snaffle up any unassigned but	 * probe-able interrupts	 */	spin_lock_irq(&irq_controller_lock);	for (i = 0; i < NR_IRQS; i++) {		if (!irq_desc[i].probe_ok || irq_desc[i].action)			continue;		irq_desc[i].probing = 1;		irq_desc[i].triggered = 0;		if (irq_desc[i].chip->set_type)			irq_desc[i].chip->set_type(i, IRQT_PROBE);		irq_desc[i].chip->unmask(i);		irqs += 1;	}	spin_unlock_irq(&irq_controller_lock);	/*	 * wait for spurious interrupts to mask themselves out again	 */	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )		/* min 100ms delay */;	/*	 * now filter out any obviously spurious interrupts	 */	spin_lock_irq(&irq_controller_lock);	for (i = 0; i < NR_IRQS; i++) {		if (irq_desc[i].probing && irq_desc[i].triggered) {			irq_desc[i].probing = 0;			irqs -= 1;		}	}	spin_unlock_irq(&irq_controller_lock);	return irqs;}EXPORT_SYMBOL(probe_irq_on);unsigned int probe_irq_mask(unsigned long irqs){	unsigned int mask = 0, i;	spin_lock_irq(&irq_controller_lock);	for (i = 0; i < 16 && i < NR_IRQS; i++)		if (irq_desc[i].probing && irq_desc[i].triggered)			mask |= 1 << i;	spin_unlock_irq(&irq_controller_lock);	up(&probe_sem);	return mask;}EXPORT_SYMBOL(probe_irq_mask);/* * Possible return values: *  >= 0 - interrupt number *    -1 - no interrupt/many interrupts */int probe_irq_off(unsigned long irqs){	unsigned int i;	int irq_found = NO_IRQ;	/*	 * look at the interrupts, and find exactly one	 * that we were probing has been triggered	 */	spin_lock_irq(&irq_controller_lock);	for (i = 0; i < NR_IRQS; i++) {		if (irq_desc[i].probing &&		    irq_desc[i].triggered) {			if (irq_found != NO_IRQ) {				irq_found = NO_IRQ;				goto out;			}			irq_found = i;		}	}	if (irq_found == -1)		irq_found = NO_IRQ;out:	spin_unlock_irq(&irq_controller_lock);	up(&probe_sem);	return irq_found;}EXPORT_SYMBOL(probe_irq_off);#ifdef CONFIG_SMPstatic void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu){	pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu);	spin_lock_irq(&irq_controller_lock);	desc->cpu = cpu;	desc->chip->set_cpu(desc, irq, cpu);	spin_unlock_irq(&irq_controller_lock);}#ifdef CONFIG_PROC_FSstatic intirq_affinity_read_proc(char *page, char **start, off_t off, int count,		       int *eof, void *data){	struct irqdesc *desc = irq_desc + ((int)data);	int len = cpumask_scnprintf(page, count, desc->affinity);	if (count - len < 2)		return -EINVAL;	page[len++] = '\n';	page[len] = '\0';	return len;}static intirq_affinity_write_proc(struct file *file, const char __user *buffer,			unsigned long count, void *data){	unsigned int irq = (unsigned int)data;	struct irqdesc *desc = irq_desc + irq;	cpumask_t affinity, tmp;	int ret = -EIO;	if (!desc->chip->set_cpu)		goto out;	ret = cpumask_parse(buffer, count, affinity);	if (ret)		goto out;	cpus_and(tmp, affinity, cpu_online_map);	if (cpus_empty(tmp)) {		ret = -EINVAL;		goto out;	}	desc->affinity = affinity;	route_irq(desc, irq, first_cpu(tmp));	ret = count; out:	return ret;}#endif#endifvoid __init init_irq_proc(void){#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)	struct proc_dir_entry *dir;	int irq;	dir = proc_mkdir("irq", NULL);	if (!dir)		return;	for (irq = 0; irq < NR_IRQS; irq++) {		struct proc_dir_entry *entry;		struct irqdesc *desc;		char name[16];		desc = irq_desc + irq;		memset(name, 0, sizeof(name));		snprintf(name, sizeof(name) - 1, "%u", irq);		desc->procdir = proc_mkdir(name, dir);		if (!desc->procdir)			continue;		entry = create_proc_entry("smp_affinity", 0600, desc->procdir);		if (entry) {			entry->nlink = 1;			entry->data = (void *)irq;			entry->read_proc = irq_affinity_read_proc;			entry->write_proc = irq_affinity_write_proc;		}	}#endif}void __init init_IRQ(void){	struct irqdesc *desc;	extern void init_dma(void);	int irq;#ifdef CONFIG_SMP	bad_irq_desc.affinity = CPU_MASK_ALL;	bad_irq_desc.cpu = smp_processor_id();#endif	for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {		*desc = bad_irq_desc;		INIT_LIST_HEAD(&desc->pend);	}	init_arch_irq();	init_dma();}static int __init noirqdebug_setup(char *str){	noirqdebug = 1;	return 1;}__setup("noirqdebug", noirqdebug_setup);#ifdef CONFIG_HOTPLUG_CPU/* * The CPU has been marked offline.  Migrate IRQs off this CPU.  If * the affinity settings do not allow other CPUs, force them onto any * available CPU. */void migrate_irqs(void){	unsigned int i, cpu = smp_processor_id();	for (i = 0; i < NR_IRQS; i++) {		struct irqdesc *desc = irq_desc + i;		if (desc->cpu == cpu) {			unsigned int newcpu = any_online_cpu(desc->affinity);			if (newcpu == NR_CPUS) {				if (printk_ratelimit())					printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",					       i, cpu);				cpus_setall(desc->affinity);				newcpu = any_online_cpu(desc->affinity);			}			route_irq(desc, i, newcpu);		}	}}#endif /* CONFIG_HOTPLUG_CPU */

⌨️ 快捷键说明

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