📄 irq.c
字号:
irqreturn_t (*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 (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); }#endif if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) 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 = CPU_MASK_NONE; 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){ struct irq_source *source; struct irq_group *group; struct irq_level *level; struct irqaction **p, **pp; unsigned long flags; if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) return; group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; if (!group) BUG(); source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; if (!source) BUG(); level = source->level; p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; spin_lock_irqsave(&level->lock, flags); for (pp = p; *pp; pp = &(*pp)->next) { struct irqaction *action = *pp; if (action->dev_id != dev_id) continue; /* found it - remove from the list of entries */ *pp = action->next; level->usage--; if (p == pp && group->control) group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 0); if (level->usage == 0) __set_MASK(level - frv_irq_levels); spin_unlock_irqrestore(&level->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; }}/* * IRQ autodetection code.. * * This depends on the fact that any interrupt that comes in on to an * unassigned IRQ will cause GxICR_DETECT to be set */static DECLARE_MUTEX(probe_sem);/** * probe_irq_on - begin an interrupt autodetect * * Commence probing for an interrupt. The interrupts are scanned * and a mask of potential interrupt lines is returned. * */unsigned long probe_irq_on(void){ down(&probe_sem); return 0;}/* * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). *//** * probe_irq_mask - scan a bitmap of interrupt lines * @val: mask of interrupts to consider * * Scan the ISA bus interrupt lines and return a bitmap of * active interrupts. The interrupt probe logic state is then * returned to its previous value. * * Note: we need to scan all the irq's even though we will * only return ISA irq numbers - just so that we reset them * all to a known state. */unsigned int probe_irq_mask(unsigned long xmask){ up(&probe_sem); return 0;}/* * Return the one interrupt that triggered (this can * handle any interrupt source). *//** * probe_irq_off - end an interrupt autodetect * @xmask: mask of potential interrupts (unused) * * Scans the unused interrupt lines and returns the line which * appears to have triggered the interrupt. If no interrupt was * found then zero is returned. If more than one interrupt is * found then minus the first candidate is returned to indicate * their is doubt. * * The interrupt probe logic state is returned to its previous * value. * * BUGS: When used in a module (which arguably shouldnt happen) * nothing prevents two IRQ probe callers from overlapping. The * results of this are non-optimal. */int probe_irq_off(unsigned long xmask){ up(&probe_sem); return -1;}/* this was setup_x86_irq but it seems pretty generic */int setup_irq(unsigned int irq, struct irqaction *new){ struct irq_source *source; struct irq_group *group; struct irq_level *level; struct irqaction **p, **pp; unsigned long flags; group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; if (!group) BUG(); source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; if (!source) BUG(); level = source->level; p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; /* * 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); } /* must juggle the interrupt processing stuff with interrupts disabled */ spin_lock_irqsave(&level->lock, flags); /* can't share interrupts unless all parties agree to */ if (level->usage != 0 && !(level->flags & new->flags & SA_SHIRQ)) { spin_unlock_irqrestore(&level->lock,flags); return -EBUSY; } /* add new interrupt at end of irq queue */ pp = p; while (*pp) pp = &(*pp)->next; *pp = new; level->usage++; level->flags = new->flags; /* turn the interrupts on */ if (level->usage == 1) __clr_MASK(level - frv_irq_levels); if (p == pp && group->control) group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 1); spin_unlock_irqrestore(&level->lock, flags); register_irq_proc(irq); return 0;}static struct proc_dir_entry * root_irq_dir;static struct proc_dir_entry * irq_dir [NR_IRQS];#define HEX_DIGITS 8static unsigned int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret){ unsigned char hexnum [HEX_DIGITS]; unsigned long value; int i; if (!count) return -EINVAL; if (count > HEX_DIGITS) count = HEX_DIGITS; if (copy_from_user(hexnum, buffer, count)) return -EFAULT; /* * Parse the first 8 characters as a hex string, any non-hex char * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. */ value = 0; for (i = 0; i < count; i++) { unsigned int c = hexnum[i]; switch (c) { case '0' ... '9': c -= '0'; break; case 'a' ... 'f': c -= 'a'-10; break; case 'A' ... 'F': c -= 'A'-10; break; default: goto out; } value = (value << 4) | c; }out: *ret = value; return 0;}static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ unsigned long *mask = (unsigned long *) data; if (count < HEX_DIGITS+1) return -EINVAL; return sprintf (page, "%08lx\n", *mask);}static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, unsigned long count, void *data){ unsigned long *mask = (unsigned long *) data, full_count = count, err; unsigned long new_value; show_state(); err = parse_hex_value(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){ char name [MAX_NAMELEN]; if (!root_irq_dir || 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);}unsigned long prof_cpu_mask = -1;void 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); if (!entry) return; 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);}/*****************************************************************************//* * initialise the interrupt system */void __init init_IRQ(void){ route_cpu_irqs(); fpga_init();#ifdef CONFIG_FUJITSU_MB93493 route_mb93493_irqs();#endif} /* end init_IRQ() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -