/* * 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 */ } } }
/* * Unregister the handler for a given RETU interrupt source. */ void retu_free_irq(int id) { struct retu_irq_handler_desc *hnd; if (id >= MAX_RETU_IRQ_HANDLERS) { printk(KERN_ERR PFX "Invalid argument to %s\n", __FUNCTION__); return; } hnd = &retu_irq_handlers[id]; if (hnd->func == NULL) { printk(KERN_ERR PFX "IRQ %d already freed\n", id); return; } retu_disable_irq(id); hnd->func = NULL; }
static void retu_headset_det_disable(struct retu_headset *hs) { unsigned long flags; mutex_lock(&hs->mutex); if (hs->detection_enabled) { hs->detection_enabled = 0; retu_disable_irq(RETU_INT_HOOK); del_timer_sync(&hs->enable_timer); del_timer_sync(&hs->detect_timer); spin_lock_irqsave(&hs->lock, flags); if (hs->pressed) input_report_key(hs->idev, RETU_HEADSET_KEY, 0); spin_unlock_irqrestore(&hs->lock, flags); retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8)); } mutex_unlock(&hs->mutex); }
static int __init retu_headset_probe(struct platform_device *pdev) { struct retu_headset *hs; int r; hs = kzalloc(sizeof(*hs), GFP_KERNEL); if (hs == NULL) return -ENOMEM; hs->pdev = pdev; hs->idev = input_allocate_device(); if (hs->idev == NULL) { r = -ENOMEM; goto err1; } hs->idev->name = "retu-headset"; hs->idev->dev.parent = &pdev->dev; set_bit(EV_KEY, hs->idev->evbit); set_bit(RETU_HEADSET_KEY, hs->idev->keybit); r = input_register_device(hs->idev); if (r < 0) goto err2; r = device_create_file(&pdev->dev, &dev_attr_hookdet); if (r < 0) goto err3; r = device_create_file(&pdev->dev, &dev_attr_enable); if (r < 0) goto err4; r = device_create_file(&pdev->dev, &dev_attr_enable_det); if (r < 0) goto err5; platform_set_drvdata(pdev, hs); spin_lock_init(&hs->lock); mutex_init(&hs->mutex); setup_timer(&hs->enable_timer, retu_headset_enable_timer, (unsigned long) hs); setup_timer(&hs->detect_timer, retu_headset_detect_timer, (unsigned long) hs); r = retu_request_irq(RETU_INT_HOOK, retu_headset_hook_interrupt, (unsigned long) hs, "hookdet"); if (r != 0) { dev_err(&pdev->dev, "hookdet IRQ not available\n"); goto err6; } retu_disable_irq(RETU_INT_HOOK); return 0; err6: device_remove_file(&pdev->dev, &dev_attr_enable_det); err5: device_remove_file(&pdev->dev, &dev_attr_enable); err4: device_remove_file(&pdev->dev, &dev_attr_hookdet); err3: input_unregister_device(hs->idev); err2: input_free_device(hs->idev); err1: kfree(hs); return r; }