/***************************************************************************************\

File Name:      mtx_irq.c

Description:    Interruption routine support for MTX devices.

References:     None.

Author:         Karl Lessard    <klessard@matrox.com>

    Copyright (c) 2003, Matrox Graphics Inc.
    All Rights Reserved.

\***************************************************************************************/

#define __NO_VERSION__
#include "mtx_drv.h"

#ifdef KERNEL_2_4
#define     IRQ_NONE
#define     IRQ_HANDLED
#endif

DECLARE_TASKLET(mtx_empty_tasklet, NULL, 0);

/***************************************************************************************
 * Function:       mtx_irq_interrupt
 *
 * Description:    Top half routine for all type of interruption.
 *
 * Parameters:     irq          IRQ number
 *                 dev_id       Parameter to our routine
 *                 regs         Not used (registers of interrupted context)
 *  
 * Return Value:   0 if succeed, errno otherwise for kernel 2.4
                   IRQ_HANDLED if succeed, IRQ_NONE otherewhis for kernel 2.6
 *
 * Comments:       None.
 */
IRQReturnType mtx_irq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    mtx_device_t *dev = (mtx_device_t*)dev_id;
    int ret;

    /* Call top-half of core interrupt routine */
    ret = dev->core->irq_fast(dev->core_data);

    if (ret < 0) 
    {   /* We don't own the interrupt or an error occured, return immediately */
        return IRQ_NONE;
    }
    
    if (ret > 0)
    {   /* We want the bottom-half routine to be schedule */
        tasklet_schedule(&dev->irq_bh);
    }

    return IRQ_HANDLED;
}

/***************************************************************************************
 * Function:       mtx_irq_init
 *
 * Description:    Request interrupt line for our device and initialize device data
 *                 to be ready to handle IRQs.
 *
 * Parameters:     dev          MTX device
 *  
 * Return Value:   0 if succeed, errno otherwise.
 *
 * Comments:       None.
 */
int
mtx_irq_init(mtx_device_t *dev)
{
    int ret;

    /* Request IRQ line */
    /* TODO fix the sharing problem*/
    ret = request_irq(dev->pci_dev->irq, mtx_irq_interrupt, SA_SHIRQ, GetPciName(dev->pci_dev), dev);

    if (ret < 0)
    {
        MTX_WARNING("Failed to request IRQ %u for device 0x%04x, some feature will"
                    " not work properly\n", dev->pci_dev->irq, dev->pci_dev->device);
        return ret;
    }

    /* Init bottom half tasklet */
    memcpy(&dev->irq_bh, &mtx_empty_tasklet, sizeof(mtx_empty_tasklet));

    dev->irq_bh.func = dev->core->irq_slow;
    dev->irq_bh.data = (unsigned long)dev->core_data;

    dev->irq_enable = 1;

    return 0;
}

/***************************************************************************************
 * Function:       mtx_irq_cleanup
 *
 * Description:    Free interrupt line and cleanup IRQ device data.
 *
 * Parameters:     dev          MTX device
 *  
 * Return Value:   None.
 *
 * Comments:       None.
 */
void
mtx_irq_cleanup(mtx_device_t *dev)
{
    if (!dev->irq_enable)
        return; /* nothing to do */

    /* Free IRQ line */
    free_irq(dev->pci_dev->irq, dev);

    /* Cleanup device data */
    memcpy(&dev->irq_bh, &mtx_empty_tasklet, sizeof(mtx_empty_tasklet));
    dev->irq_enable = 0;
}
