Esempio n. 1
0
/*******************************************************************************
 *
 * Function   :  Plx_cleanup_module
 *
 * Description:  Unload the driver
 *
 ******************************************************************************/
void
Plx_cleanup_module(
    void
)
{
    DebugPrintf_Cont(("\n"));
    DebugPrintf(("Unload driver...\n"));

    // Release common buffer
    if (pGbl_DriverObject->CommonBuffer.Size != 0)
    {
        DebugPrintf(("De-allocate Common Buffer\n"));

        // Release the buffer
        Plx_dma_buffer_free(
            pGbl_DriverObject->DeviceObject->DeviceExtension,   // First device
            &(pGbl_DriverObject->CommonBuffer)
        );
    }

    // De-register driver
    if (pGbl_DriverObject->bPciDriverReg)
        pci_unregister_driver( &PlxPciDriver );

    DebugPrintf((
                    "De-register driver (MajorID = %03d)\n",
                    pGbl_DriverObject->MajorID
                ));

    /*********************************************************
     * De-register the driver with the OS
     *
     * NOTE: This driver still uses the old method for de-registering
     * the device (unregister_chrdev) for compatability with 2.4 kernels.
     * A future version of the driver may use the new interface
     * (cdev_init, cdev_add, & cdev_del).
     ********************************************************/
    unregister_chrdev(
        pGbl_DriverObject->MajorID,
        PLX_DRIVER_NAME
    );

    DebugPrintf((
                    "Release global driver object (%p)\n",
                    pGbl_DriverObject
                ));

    // Release driver object
    kfree( pGbl_DriverObject );
    pGbl_DriverObject = NULL;

    DebugPrintf(("...driver unloaded\n"));
}
Esempio n. 2
0
/******************************************************************************
 *
 * Function   :  Dispatch_release
 *
 * Description:  Handle close() call, which closes the connection between the
 *               application and drivers.
 *
 ******************************************************************************/
int
Dispatch_release(
    struct inode *inode,
    struct file  *filp
    )
{
    DEVICE_OBJECT *fdo;


    DebugPrintf_Cont(("\n"));
    DebugPrintf(("Received message ==> CLOSE_DEVICE\n"));

    if (iminor(inode) == PLX_MNGMT_INTERFACE)
    {
        DebugPrintf(("Close Management interface...\n"));

        // Clear the driver object from the private data
        filp->private_data = NULL;
    }
    else
    {
        // Get the device object
        fdo = (DEVICE_OBJECT *)(filp->private_data);

        DebugPrintf((
            "Close device (%s)...\n",
            fdo->DeviceExtension->LinkName
            ));

        // Release any pending notifications owned by proccess
        PlxNotificationCancel(
            fdo->DeviceExtension,
            NULL,
            filp
            );

        // Close DMA channels owned by the process
        PlxDmaChannelCleanup(
            fdo->DeviceExtension,
            filp
            );

        // Release any physical memory allocated by process
        PlxPciPhysicalMemoryFreeAll_ByOwner(
            fdo->DeviceExtension,
            filp
            );
    }

    DebugPrintf(("...device closed\n"));

    return 0;
}
Esempio n. 3
0
/******************************************************************************
 *
 * Function   :  Dispatch_open
 *
 * Description:  Handle open() which allows applications to create a
 *               connection to the driver
 *
 ******************************************************************************/
int
Dispatch_open(
    struct inode *inode,
    struct file  *filp
    )
{
    U8             i;
    DEVICE_OBJECT *fdo;


    DebugPrintf_Cont(("\n"));
    DebugPrintf(("Received message ==> OPEN_DEVICE\n"));

    if (iminor(inode) == PLX_MNGMT_INTERFACE)
    {
        DebugPrintf(("Open Management interface...\n"));

        // Store the driver object in the private data
        filp->private_data = pGbl_DriverObject;
    }
    else
    {
        // Select desired device from device list
        i   = iminor(inode);
        fdo = pGbl_DriverObject->DeviceObject;

        while (i-- && fdo != NULL)
           fdo = fdo->NextDevice;

        if (fdo == NULL)
        {
            ErrorPrintf(("WARNING - Attempt to open non-existent device\n"));
            return (-ENODEV);
        }

        DebugPrintf((
            "Open device (%s)...\n",
            fdo->DeviceExtension->LinkName
            ));

        // Store device object for future calls
        filp->private_data = fdo;
    }

    DebugPrintf(("...device opened\n"));

    return 0;
}
Esempio n. 4
0
/******************************************************************************
 *
 * Function   :  Dispatch_mmap
 *
 * Description:  Maps a PCI space into user virtual space
 *
 ******************************************************************************/
int
Dispatch_mmap(
    struct file           *filp,
    struct vm_area_struct *vma
    )
{
    int               rc;
    off_t             offset;
    BOOLEAN           bDeviceMem;
    PLX_UINT_PTR      AddressToMap;
    DEVICE_EXTENSION *pdx;


    DebugPrintf_Cont(("\n"));
    DebugPrintf(("Received message ===> MMAP\n"));

    // Get device extension
    pdx = ((DEVICE_OBJECT*)(filp->private_data))->DeviceExtension;

    // Get the supplied offset
    offset = vma->vm_pgoff;

    // Determine if mapping to a PCI BAR or system memory
    switch (offset)
    {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
            // Verify space is not I/O
            if (pdx->PciBar[offset].Properties.Flags & PLX_BAR_FLAG_IO)
            {
                DebugPrintf((
                    "ERROR - PCI BAR %d is an I/O space, cannot map to user space\n",
                    (U8)offset
                    ));

                return -ENODEV;
            }

            DebugPrintf((
                "Map PCI BAR %d...\n",
                (U8)offset
                ));

            // Use the BAR physical address for the mapping
            AddressToMap = (PLX_UINT_PTR)pdx->PciBar[offset].Properties.Physical;

            // Flag that the mapping is to IO memory
            bDeviceMem = TRUE;
            break;

        default:
            // Use provided offset as CPU physical address for mapping
            AddressToMap = (PLX_UINT_PTR)offset << PAGE_SHIFT;

            // Flag that the mapping is to system memory
            bDeviceMem = FALSE;
            break;
    }

    // Verify physical address
    if (AddressToMap == 0)
    {
        DebugPrintf((
            "ERROR - Invalid physical (%08lx), cannot map to user space\n",
            AddressToMap
            ));

        return -ENODEV;
    }

    /***********************************************************
     * Attempt to map the region
     *
     * NOTE:
     *
     * Due to variations in the remap function between kernel releases
     * and distributions, a PLX macro is used to simplify code
     * readability.  For additional information about the macro
     * expansions, refer to the file "Plx_sysdep.h".
     **********************************************************/

    // Set the region as page-locked
    vma->vm_flags |= VM_RESERVED;

    if (bDeviceMem)
    {
        // Set flag for I/O resource
        vma->vm_flags |= VM_IO;

        // The region must be marked as non-cached
        vma->vm_page_prot =
            pgprot_noncached(
                vma->vm_page_prot
                );

        // Map device memory
        rc =
            Plx_io_remap_pfn_range(
                vma,
                vma->vm_start,
                AddressToMap >> PAGE_SHIFT,
                vma->vm_end - vma->vm_start,
                vma->vm_page_prot
                );
    }
    else
    {
Esempio n. 5
0
/*******************************************************************************
 *
 * Function   :  Plx_init_module
 *
 * Description:  Entry point for the driver
 *
 ******************************************************************************/
int __init
Plx_init_module(
    void
)
{
    int              status;
    PLX_PHYSICAL_MEM PhysicalMem;


    DebugPrintf_Cont(("\n"));
    DebugPrintf(("<========================================================>\n"));
    printk(
        "PLX driver v%d.%02d (%d-bit) - built on %s %s\n",
        PLX_SDK_VERSION_MAJOR, PLX_SDK_VERSION_MINOR,
        (U32)(sizeof(PLX_UINT_PTR) * 8),
        __DATE__, __TIME__
    );

    printk(
        "Supports Linux kernel version %s\n",
        UTS_RELEASE
    );

    // Allocate memory for the Driver Object
    pGbl_DriverObject =
        kmalloc(
            sizeof(DRIVER_OBJECT),
            GFP_KERNEL
        );

    if (pGbl_DriverObject == NULL)
    {
        ErrorPrintf(("ERROR - memory allocation for Driver Object failed\n"));
        return (-ENOMEM);
    }

    printk(
        "Allocated global driver object (%p)\n",
        pGbl_DriverObject
    );

    // Clear the driver object
    RtlZeroMemory(
        pGbl_DriverObject,
        sizeof(DRIVER_OBJECT)
    );

    // Initialize driver object
    pGbl_DriverObject->DeviceObject = NULL;
    pGbl_DriverObject->DeviceCount  = 0;

    // Fill in the appropriate dispatch handlers
    pGbl_DriverObject->DispatchTable.owner   = THIS_MODULE;
    pGbl_DriverObject->DispatchTable.mmap    = Dispatch_mmap;
    pGbl_DriverObject->DispatchTable.open    = Dispatch_open;
    pGbl_DriverObject->DispatchTable.release = Dispatch_release;

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36))
    pGbl_DriverObject->DispatchTable.ioctl = Dispatch_IoControl;
#else
    pGbl_DriverObject->DispatchTable.unlocked_ioctl = Dispatch_IoControl;
#endif

    // Initialize spin locks
    spin_lock_init(
        &(pGbl_DriverObject->Lock_DeviceList)
    );

    /*********************************************************
     * Register the driver with the OS
     *
     * NOTE: This driver still uses the old method for registering
     * the device (register_chrdev) for compatability with 2.4 kernels.
     * A future version of the driver may use the new interface
     * (cdev_init, cdev_add, & cdev_del).
     ********************************************************/
    pGbl_DriverObject->MajorID =
        register_chrdev(
            0,              // 0 = system chooses Major ID
            PLX_DRIVER_NAME,
            &(pGbl_DriverObject->DispatchTable)
        );

    printk(
        "Registered driver (MajorID = %03d)\n",
        pGbl_DriverObject->MajorID
    );

    // Register the driver
    status = pci_register_driver( &PlxPciDriver );

    if (status != 0)
    {
        ErrorPrintf(("ERROR: Unable to register driver (status=%d)\n", status));
        Plx_cleanup_module();
        return status;
    }

    // Flag driver was registered
    pGbl_DriverObject->bPciDriverReg = TRUE;

    // Check if any devices were found
    if (pGbl_DriverObject->DeviceCount == 0)
    {
        ErrorPrintf(("ERROR - No supported devices found\n"));
        Plx_cleanup_module();
        return (-ENODEV);
    }

    // Initialize common buffer
    pGbl_DriverObject->CommonBuffer.Size = 0;

    // Set requested size
    PhysicalMem.Size = DEFAULT_SIZE_COMMON_BUFFER;

    // Allocate common buffer
    if (PhysicalMem.Size != 0)
    {
        // Allocate common buffer
        PlxPciPhysicalMemoryAllocate(
            pGbl_DriverObject->DeviceObject->DeviceExtension,  // Assign buffer to first device
            &PhysicalMem,
            TRUE,                                              // Smaller buffer is ok
            pGbl_DriverObject                                  // Assign Driver object as owner
        );
    }

    DebugPrintf(( "Added: %d supported device(s)\n", pGbl_DriverObject->DeviceCount ));
    DebugPrintf(("...driver loaded\n\n"));
    return 0;
}