www.pudn.com > PlxSdk.rar > Plx_sysdep.h


#ifndef _PLX_SYSDEP_H_
#define _PLX_SYSDEP_H_

/******************************************************************************
 *
 * File Name:
 *
 *      Plx_sysdep.h
 *
 * Description:
 *
 *      This file is provided to support compatible code between different
 *      Linux kernel versions.
 *
 * Revision History:
 *
 *      04-01-07 : PLX SDK v5.00
 *
 *****************************************************************************/


#ifndef LINUX_VERSION_CODE
    #include 
#endif


// Only allow 2.4 and 2.6 kernels
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    #error "Linux kernel versions before v2.4 not supported"
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,7,0)
    #error "Linux kernel versions greater than v2.6 not supported"
#endif


// Detect current version
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
    #define LINUX_24
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,7,0)
    #define LINUX_26
#else
    #error "Unable to determine Linux kernel support"
#endif


// Missing definitions in 2.4
#if defined(LINUX_24)
    #define __user
    #define __GFP_NOWARN                0
    #define DMA_TO_DEVICE               1
    #define DMA_FROM_DEVICE             2
    #define iminor(inode)               MINOR((inode)->i_rdev)
    #define imajor(inode)               MAJOR((inode)->i_rdev)
    #define pgprot_noncached(x)         (x)

    // ISR returns nothing in kernel 2.4
    #define irqreturn_t                 void
    #define PLX_IRQ_RETVAL(value)
#else
    #define PLX_IRQ_RETVAL              IRQ_RETVAL
#endif




/***********************************************************
 * INIT_WORK
 *
 * This macro initializes a work structure with the function
 * to call.  In kernel 2.6.20, the 3rd parameter was removed.
 * It used to be the parameter to the function, but now, the
 * function is called with a pointer to the work_struct itself.
 **********************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
    #define PLX_INIT_WORK                     INIT_WORK
#else
    #define PLX_INIT_WORK(work, func, data)   INIT_WORK((work), (func))
#endif




/***********************************************************
 * PLX_DPC_PARAM
 *
 * In kernel 2.6.20, the parameter to a work queue function
 * was made to always be a pointer to the work_struct itself.
 * In previous kernels, this was always a VOID*.  Since
 * PLX drivers use work queue functions for the DPC/bottom-half
 * processing, the parameter had to be changed.  For cleaner
 * source code, the definition PLX_DPC_PARAM is used and is
 * defined below.  This also allows 2.4.x compatible source code.
 **********************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
    #define PLX_DPC_PARAM      VOID
#else
    #define PLX_DPC_PARAM      struct work_struct
#endif




/***********************************************************
 * dma_set_mask
 *
 * This function is used to set the mask for DMA addresses
 * for the device.  In 2.4 kernels, the function is pci_set_dma_mask
 * and in 2.6 kernels, it has been change to dma_set_mask.
 * In addition to the name change, the first parameter has
 * been changed from the PCI device structure in 2.4, to
 * the device structure found in the PCI device structure.
 **********************************************************/
#if defined(LINUX_24)
    #define Plx_dma_set_mask(pdx, mask) \
            (                           \
                pci_set_dma_mask(       \
                    (pdx)->pPciDevice,  \
                    (mask)              \
                    )                   \
            )
#else
    #define Plx_dma_set_mask(pdx, mask)        \
            (                                  \
                dma_set_mask(                  \
                    &((pdx)->pPciDevice->dev), \
                    (mask)                     \
                    )                          \
            )
#endif




/***********************************************************
 * dma_alloc_coherent & dma_free_coherent
 *
 * These functions are used to allocate and map DMA buffers.
 * In 2.4 kernels, the functions are pci_alloc/free_consistent
 * and in 2.6 kernels, they have been changed to
 * dma_alloc/free_coherent.  In addition to the name changes,
 * the first parameter has been changed from the PCI device
 * structure in 2.4, to the device structure found in the PCI
 * device structure.
 **********************************************************/
#if defined(LINUX_24)
    #define Plx_dma_alloc_coherent(pdx, size, dma_handle, flag) \
            (                          \
                pci_alloc_consistent(  \
                    (pdx)->pPciDevice, \
                    (size),            \
                    (dma_handle)       \
                    )                  \
            )

    #define Plx_dma_free_coherent(pdx, size, cpu_addr, dma_handle) \
            (                          \
                pci_free_consistent(   \
                    (pdx)->pPciDevice, \
                    (size),            \
                    (cpu_addr),        \
                    (dma_handle)       \
                    )                  \
            )
#else
    #define Plx_dma_alloc_coherent(pdx, size, dma_handle, flag) \
            (                                  \
                dma_alloc_coherent(            \
                    &((pdx)->pPciDevice->dev), \
                    (size),                    \
                    (dma_handle),              \
                    (flag)                     \
                    )                          \
            )

    #define Plx_dma_free_coherent(pdx, size, cpu_addr, dma_handle) \
            (                                  \
                dma_free_coherent(             \
                    &((pdx)->pPciDevice->dev), \
                    (size),                    \
                    (cpu_addr),                \
                    (dma_handle)               \
                    )                          \
            )
#endif




/***********************************************************
 * dma_map_page & dma_unmap_page
 *
 * These functions are used to map a single user buffer page
 * in order to get a valid bus address for the page. In 2.4
 * kernels, the functions are pci_map/unmap_page and in 2.6
 * kernels, they have been changed to dma_map/unmap_page.
 * In addition to the name changes, the first parameter has
 * been changed from the PCI device structure in 2.4, to the
 * device structure found in the PCI device structure.
 **********************************************************/
#if defined(LINUX_24)
    #define Plx_dma_map_page(pdx, page, offset, size, direction) \
            (                          \
                pci_map_page(          \
                    (pdx)->pPciDevice, \
                    (page),            \
                    (offset),          \
                    (size),            \
                    (direction)        \
                    )                  \
            )

    #define Plx_dma_unmap_page(pdx, dma_address, size, direction) \
            (                          \
                pci_unmap_page(        \
                    (pdx)->pPciDevice, \
                    (dma_address),     \
                    (size),            \
                    (direction)        \
                    )                  \
            )
#else
    #define Plx_dma_map_page(pdx, page, offset, size, direction) \
            (                                  \
                dma_map_page(                  \
                    &((pdx)->pPciDevice->dev), \
                    (page),                    \
                    (offset),                  \
                    (size),                    \
                    (direction)                \
                    )                          \
            )

    #define Plx_dma_unmap_page(pdx, dma_address, size, direction) \
            (                          \
                dma_unmap_page(                \
                    &((pdx)->pPciDevice->dev), \
                    (dma_address),     \
                    (size),            \
                    (direction)        \
                    )                  \
            )
#endif




/***********************************************************
 * remap_pfn_range & remap_page_range
 *
 * The remap_pfn_range() function was added in kernel 2.6 and
 * does not exist in previous kernels.  For older kernels,
 * remap_page_range can be used, as it is the same function
 * except the Page Frame Number (pfn) parameter should
 * actually be a physical address.  For that case, the
 * pfn is simply shifted by PAGE_SHIFT to obtain the
 * corresponding physical address.
 *
 * remap_pfn_range, however, does not seem to exist in all
 * kernel 2.6 distributions.  remap_page_range was officially
 * removed in 2.6.11.  To keep things simple, this driver
 * will default to using remap_page_range unless the kernel
 * version is 2.6.11 or greater.
 *
 * For 2.4 kernels, remap_pfn_range obviously does not exist.
 * Although remap_page_range() may be used instead, there
 * was a parameter added in kernel version 2.5.3. The new
 * parameter is a pointer to the VMA structure.  To make
 * matters even more complicated, the kernel source in
 * RedHat 9.0 (v2.4.20-8), however, also uses the new
 * parameter.  As a result, another #define is added if
 * RedHat 9.0 kernel source is used.
 *
 * The #defines below should result in the following usage table:
 *
 *  kernel                        function
 * ====================================================
 *  2.4.0  -> 2.4.19              remap_page_range (no VMA param)
 *  2.4.20 -> 2.5.2  (non-RedHat) remap_page_range (no VMA param)
 *  2.4.20 -> 2.5.2  (RedHat)     remap_page_range (with VMA param)
 *  2.5.3  -> 2.6.10              remap_page_range (with VMA param)
 *  2.6.11 & up                   remap_pfn_range
 *
 **********************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
    #if ( (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)) || \
         ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)) && defined(RED_HAT_LINUX_KERNEL)) )

        // Revert to remap_page_range
        #define Plx_remap_pfn_range(vma, virt_addr, pfn, size, prot) \
                (                           \
                    remap_page_range(       \
                        (vma),              \
                        (virt_addr),        \
                        (pfn) << PAGE_SHIFT,\
                        (size),             \
                        (prot)              \
                        )                   \
                )
    #else
        // VMA parameter must be removed
        #define Plx_remap_pfn_range(vma, virt_addr, pfn, size, prot) \
                (                           \
                    remap_page_range(       \
                        (virt_addr),        \
                        (pfn) << PAGE_SHIFT,\
                        (size),             \
                        (prot)              \
                        )                   \
                )
    #endif
#else
    // Function already defined
    #define Plx_remap_pfn_range         remap_pfn_range
#endif




/***********************************************************
 * io_remap_pfn_range & io_remap_page_range
 *
 * The io_remap_page_range() function is used to map I/O space
 * into user mode.  Generally, it defaults to remap_page_range,
 * but on some architectures it performs platform-specific code.
 *
 * In kernel 2.6.12, io_remap_page_range was deprecated and
 * replaced with io_remap_pfn_range.
 *
 * Since io_remap_xxx_range usually reverts to remap_xxx_range,
 * the same issues regarding kernel version apply.  Refer to
 * the explanation above regarding remap_page/pfn_range.
 *
 * The #defines below should result in the following usage table:
 *
 *  kernel                        function
 * ====================================================
 *  2.4.0  -> 2.4.19              io_remap_page_range (no VMA param)
 *  2.4.20 -> 2.5.2  (non-RedHat) io_remap_page_range (no VMA param)
 *  2.4.20 -> 2.5.2  (RedHat)     io_remap_page_range (with VMA param)
 *  2.5.3  -> 2.6.11              io_remap_page_range (with VMA param)
 *  2.6.12 & up                   io_remap_pfn_range
 *
 **********************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
    #if ( (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)) || \
         ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)) && defined(RED_HAT_LINUX_KERNEL)) )

        // Revert to io_remap_page_range (with VMA)
        #define Plx_io_remap_pfn_range(vma, virt_addr, pfn, size, prot) \
                (                           \
                    io_remap_page_range(    \
                        (vma),              \
                        (virt_addr),        \
                        (pfn) << PAGE_SHIFT,\
                        (size),             \
                        (prot)              \
                        )                   \
                )
    #else
        // Revert to io_remap_page_range (without VMA)
        #define Plx_io_remap_pfn_range(vma, virt_addr, pfn, size, prot) \
                (                           \
                    io_remap_page_range(    \
                        (virt_addr),        \
                        (pfn) << PAGE_SHIFT,\
                        (size),             \
                        (prot)              \
                        )                   \
                )
    #endif
#else
    // Function already defined
    #define Plx_io_remap_pfn_range      io_remap_pfn_range
#endif




/**********************************************************
 * The following implements an interruptible wait_event
 * with a timeout for older kernels.  This is used instead
 * of the function interruptible_sleep_on_timeout() since
 * this is susceptible to race conditions.
 *
 *    retval == 0; timed out
 *    retval >  0; condition met or task signaled
 *                 ret=jiffies remaining before timeout
 *    retval <  0; error condition or interrupted by signal
 *********************************************************/
#if defined(LINUX_24)
    #define Plx_wait_event_interruptible_timeout(wq, condition, timeout) \
    ({                                                   \
        int __ret = timeout;                             \
                                                         \
        if (!(condition))                                \
        {                                                \
            __Plx__wait_event_interruptible_timeout(     \
                wq,                                      \
                condition,                               \
                __ret                                    \
                );                                       \
        }                                                \
        __ret;                                           \
    })


    #define __Plx__wait_event_interruptible_timeout(wq, condition, ret) \
    do                                               \
    {                                                \
        wait_queue_t __wait;                         \
                                                     \
        init_waitqueue_entry(&__wait, current);      \
                                                     \
        add_wait_queue(&wq, &__wait);                \
        for (;;)                                     \
        {                                            \
            set_current_state(TASK_INTERRUPTIBLE);   \
            if (condition)                           \
                break;                               \
            if (!signal_pending(current))            \
            {                                        \
                ret = schedule_timeout(ret);         \
                if (!ret)                            \
                    break;                           \
                continue;                            \
            }                                        \
            ret = -ERESTARTSYS;                      \
            break;                                   \
        }                                            \
        current->state = TASK_RUNNING;               \
        remove_wait_queue(&wq, &__wait);             \
    }                                                \
    while (0)

#else
    #define Plx_wait_event_interruptible_timeout     wait_event_interruptible_timeout
#endif



#endif  // _PLX_SYSDEP_H_