irq.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 821 行 · 第 1/2 页

C
821
字号
	if (!handler)		return -EINVAL;	action = (struct irqaction *)			kmalloc(sizeof(struct irqaction), GFP_KERNEL);	if (!action)		return -ENOMEM;	action->handler = handler;	action->flags = irqflags;	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);int um_request_irq(unsigned int irq, int fd, int type,		   void (*handler)(int, void *, struct pt_regs *),		   unsigned long irqflags, const char * devname,		   void *dev_id){	int retval;	retval = request_irq(irq, handler, irqflags, devname, dev_id);	if(retval) return(retval);	return(activate_fd(irq, fd, type, dev_id));}/* this was setup_x86_irq but it seems pretty generic */int setup_irq(unsigned int irq, struct irqaction * new){	int shared = 0;	unsigned long flags;	struct irqaction *old, **p;	irq_desc_t *desc = irq_desc + irq;	/*	 * 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	 */	spin_lock_irqsave(&desc->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(&desc->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->depth = 0;		desc->status &= ~IRQ_DISABLED;		desc->handler->startup(irq);	}	spin_unlock_irqrestore(&desc->lock,flags);	register_irq_proc(irq);	return 0;}/** *	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);			}			free_irq_by_irq_and_dev(irq, dev_id);			spin_unlock_irqrestore(&desc->lock,flags);			/* Wait to make sure it's not being used on another CPU */			synchronize_irq(irq);			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);/* These are initialized by sysctl_init, which is called from init/main.c */static struct proc_dir_entry * root_irq_dir;static struct proc_dir_entry * irq_dir [NR_IRQS];static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];/* These are read and written as longs, so a read won't see a partial write * even during a race. */static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };static int irq_affinity_read_proc (char *page, char **start, off_t off,			int count, int *eof, void *data){	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);	if (count - len < 2)		return -EINVAL;	len += sprintf(page + len, "\n");	return len;}static int irq_affinity_write_proc (struct file *file, const char *buffer,					unsigned long count, void *data){	int irq = (long) data, full_count = count, err;	cpumask_t new_value, tmp;	if (!irq_desc[irq].handler->set_affinity)		return -EIO;	err = cpumask_parse(buffer, count, new_value);#ifdef CONFIG_SMP	/*	 * Do not allow disabling IRQs completely - it's a too easy	 * way to make the system unusable accidentally :-) At least	 * one online CPU still has to be targeted.	 */	cpus_and(tmp, new_value, cpu_online_map);	if (cpus_empty(tmp))		return -EINVAL;#endif	irq_affinity[irq] = new_value;	irq_desc[irq].handler->set_affinity(irq, new_value);	return full_count;}static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,			int count, int *eof, void *data){	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);	if (count - len < 2)		return -EINVAL;	len += sprintf(page + len, "\n");	return len;}static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,					unsigned long count, void *data){	cpumask_t *mask = (cpumask_t *)data, new_value;	unsigned long full_count = count, err;	err = cpumask_parse(buffer, count, new_value);	if (err)		return err;	*mask = new_value;	return full_count;}#define MAX_NAMELEN 10static void register_irq_proc (unsigned int irq){	struct proc_dir_entry *entry;	char name [MAX_NAMELEN];	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||	    irq_dir[irq])		return;	memset(name, 0, MAX_NAMELEN);	sprintf(name, "%d", irq);	/* create /proc/irq/1234 */	irq_dir[irq] = proc_mkdir(name, root_irq_dir);	/* create /proc/irq/1234/smp_affinity */	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);	entry->nlink = 1;	entry->data = (void *)(long)irq;	entry->read_proc = irq_affinity_read_proc;	entry->write_proc = irq_affinity_write_proc;	smp_affinity_entry[irq] = entry;}/* Read and written as a long */cpumask_t prof_cpu_mask = CPU_MASK_ALL;void __init init_irq_proc (void){	struct proc_dir_entry *entry;	int i;	/* create /proc/irq */	root_irq_dir = proc_mkdir("irq", 0);	/* create /proc/irq/prof_cpu_mask */	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);	entry->nlink = 1;	entry->data = (void *)&prof_cpu_mask;	entry->read_proc = prof_cpu_mask_read_proc;	entry->write_proc = prof_cpu_mask_write_proc;	/*	 * Create entries for all existing IRQs.	 */	for (i = 0; i < NR_IRQS; i++)		register_irq_proc(i);}static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED;unsigned long irq_lock(void){	unsigned long flags;	spin_lock_irqsave(&irq_spinlock, flags);	return(flags);}void irq_unlock(unsigned long flags){	spin_unlock_irqrestore(&irq_spinlock, flags);}unsigned long probe_irq_on(void){	return(0);}EXPORT_SYMBOL(probe_irq_on);int probe_irq_off(unsigned long val){	return(0);}EXPORT_SYMBOL(probe_irq_off);static unsigned int startup_SIGIO_irq(unsigned int irq){	return(0);}static void shutdown_SIGIO_irq(unsigned int irq){}static void enable_SIGIO_irq(unsigned int irq){}static void disable_SIGIO_irq(unsigned int irq){}static void mask_and_ack_SIGIO(unsigned int irq){}static void end_SIGIO_irq(unsigned int irq){}static unsigned int startup_SIGVTALRM_irq(unsigned int irq){	return(0);}static void shutdown_SIGVTALRM_irq(unsigned int irq){}static void enable_SIGVTALRM_irq(unsigned int irq){}static void disable_SIGVTALRM_irq(unsigned int irq){}static void mask_and_ack_SIGVTALRM(unsigned int irq){}static void end_SIGVTALRM_irq(unsigned int irq){}static struct hw_interrupt_type SIGIO_irq_type = {	"SIGIO",	startup_SIGIO_irq,	shutdown_SIGIO_irq,	enable_SIGIO_irq,	disable_SIGIO_irq,	mask_and_ack_SIGIO,	end_SIGIO_irq,	NULL};static struct hw_interrupt_type SIGVTALRM_irq_type = {	"SIGVTALRM",	startup_SIGVTALRM_irq,	shutdown_SIGVTALRM_irq,	enable_SIGVTALRM_irq,	disable_SIGVTALRM_irq,	mask_and_ack_SIGVTALRM,	end_SIGVTALRM_irq,	NULL};void __init init_IRQ(void){	int i;	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;	irq_desc[TIMER_IRQ].action = 0;	irq_desc[TIMER_IRQ].depth = 1;	irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;	enable_irq(TIMER_IRQ);	for(i=1;i<NR_IRQS;i++){		irq_desc[i].status = IRQ_DISABLED;		irq_desc[i].action = 0;		irq_desc[i].depth = 1;		irq_desc[i].handler = &SIGIO_irq_type;		enable_irq(i);	}	init_irq_signals(0);}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */

⌨️ 快捷键说明

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