/* * Register the handler for a given RETU interrupt source. */ int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name) { struct retu_irq_handler_desc *hnd; if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS || name == NULL) { printk(KERN_ERR PFX "Invalid arguments to %s\n", __FUNCTION__); return -EINVAL; } hnd = &retu_irq_handlers[id]; if (hnd->func != NULL) { printk(KERN_ERR PFX "IRQ %d already reserved\n", id); return -EBUSY; } printk(KERN_INFO PFX "Registering interrupt %d for device %s\n", id, name); hnd->func = irq_handler; hnd->arg = arg; strlcpy(hnd->name, name, sizeof(hnd->name)); retu_ack_irq(id); retu_enable_irq(id); return 0; }
/* * Tasklet handler */ static void retu_tasklet_handler(unsigned long data) { struct retu_irq_handler_desc *hnd; u16 id; u16 im; int i; for (;;) { id = retu_read_reg(RETU_REG_IDR); im = ~retu_read_reg(RETU_REG_IMR); id &= im; if (!id) break; for (i = 0; id != 0; i++, id >>= 1) { if (!(id & 1)) continue; hnd = &retu_irq_handlers[i]; if (hnd->func == NULL) { /* Spurious retu interrupt - disable and ack it */ printk(KERN_INFO "Spurious Retu interrupt " "(id %d)\n", i); retu_disable_irq(i); retu_ack_irq(i); continue; } hnd->func(hnd->arg); /* * Don't acknowledge the interrupt here * It must be done explicitly */ } } }
static void retu_headset_hook_interrupt(unsigned long arg) { struct retu_headset *hs = (struct retu_headset *) arg; unsigned long flags; retu_ack_irq(RETU_INT_HOOK); spin_lock_irqsave(&hs->lock, flags); if (!hs->pressed) { /* Headset button was just pressed down. */ hs->pressed = 1; input_report_key(hs->idev, RETU_HEADSET_KEY, 1); } spin_unlock_irqrestore(&hs->lock, flags); retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8)); mod_timer(&hs->enable_timer, jiffies + msecs_to_jiffies(50)); }
/** * Interrupt function is called whenever power button key is pressed * or released. */ static void retubutton_irq(unsigned long arg) { retu_ack_irq(RETU_INT_PWR); mod_timer(&pwrbtn_timer, jiffies + msecs_to_jiffies(PWRBTN_DELAY)); }