/*****************************************************************************/
/* Copyright (c) 2009 NXP B.V.                                               */
/*                                                                           */
/* This library is free software; you can redistribute it and/or             */
/* modify it under the terms of the GNU Lesser General Public                */
/* License as published by the Free Software Foundation, using               */
/* version 2.1 of the License.                                               */
/*                                                                           */
/* This library is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          */
/* Lesser General Public License for more details.                           */
/*                                                                           */
/* You should have received a copy of the GNU Lesser General Public          */
/* License along with this library; if not, write to the Free Software       */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phStbDFB_Init.c
    @brief  Driver init/deinit routines for DirectFB.

@b  Component:  phStbDFB.

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20050711    batelaan    First implementation.
  2 20050713    batelaan    Crosscheck fixes
  3 20050714    batelaan    Crosscheck fixes
  4 20050714    laird       Added Screen Support.
  5 20050714    laird       Remove primary registration
  6 20050718    laird       Make it choose the layer type (is hardcoded at the moment)
  7 20050719    laird       Use primary layer stuff.
  8 20050719    laird       Store the old driver data for use when calling old functions.
  9 20050823    charrett    Rename file and general cleanup
 10 20050824    charrett    Crosscheck corrections
 11 20050826    charrett    Initialise debug in driver_init_driver as well as probe
 12 20050826    charrett    Turn off all debug flags except warning.
 12.1.1 20050907 charrett   Store device pointer.
 13 20050907    laird       Adding non FBdev GFX layers
 14 20050908    laird       Merged 'phStbDFB_Init.c=13' with 'phStbDFB_Init.c=12.1.1'.
 15 20050912    charrett    Initialise the HW Acceleration code.
 16 20050913    laird       Support for the QVCP2L and layer ordering
 17 20050920    laird       Xcheck rework.
 18 20051129    laird       Adding MMIO functionality.
 19 20051214    laird       supporting our fb on non fb0 device!
 20 20060526    laird       Supporting Directfb 0.9.25 changes.
 21 20060630    laird       XCheck Changes.
 22 20060707    laird       Encoder API Changes
 23 20060720    laird       removed close call as no longer needed.
 24 20060727    laird       Removing Asserts.
----------------------------STB225----------------------------------------------
 21 20070109    laird       Moving to STB225
 22 20070116    laird       Crosscheck rework.
 23 20070131    neill       Move to NXP
 24 20070619    neill       Create LCD as separate screen
 25 20070913    neill       Add default module constructor
 26 20070928    neill       Correctly set the surface_bytepitch_alignment
 27 20071029    burningh    Improve QA C confidence factor
 28 20081111    steel       add stretch blit.
 29 20081119    neill       improve stretch blit initialisation.
 30 20090120    batelaan    Update file copyright/license text
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/

#include <phStbDFB_Local.h>

/***********************************************
* LOCAL MACROS                                 *
* recommendation only: <MODULE><_WORD>+        *
************************************************/

#define PH_STBDFB_DRIVER_NAME "NXP DirectFB Driver"
#define PH_STBDFB_VENDOR_NAME "STB225"
#define PH_STBDFB_DEVICE_NAME "PNX8335"
#define PH_STBDFB_VERSION_MAJOR 0
#define PH_STBDFB_VERSION_MINOR 1

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                [p]phStbTemplate_<Word>+_t  *
*******************************************************************/

/******************************************************************
* STATIC FUNCTION PROTOTYPES                  <Module>_<Word>+    *
*******************************************************************/
static void init_debug(void);
/******************************************************************
* STATIC DATA                  g[k|p|kp|pk|kpk]<Module>_<Word>+   *
*******************************************************************/
static bool gphStbDFB_debugInit = false;

/*********************************************************(((((((**********
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbTemplate_<Word>+ *
***************************************************************************/
/**
 * @brief debug unit
 */
DBG_UNIT(gphStbDFB_DbgUnit)

/**
 * @brief Array of screens, one for each of the renderers
 */
CoreScreen            *gpphStbDFB_Screen[PH_STBVIDEORENDERER_MAX_INSTANCES];

phStbDFB_DeviceData_t *gpphStbDFB_DeviceData;
/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          tm[<layer>]<Module>[_<Word>+] for exported functions*
********************************************************************************/
/******************************************************************************/
/* Create functions and structures required by Direct FB */
#include <core/graphics_driver.h>
DFB_GRAPHICS_DRIVER(STB225)

/******************************************************************************/
static int
driver_probe( GraphicsDevice *device )
{
    init_debug();
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);

    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
    return 1;
}

/******************************************************************************/
static void
driver_get_info( GraphicsDevice     *device,
                 GraphicsDriverInfo *info )
{
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);
    /* fill driver info structure */
    snprintf( info->name,
           DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
           PH_STBDFB_DRIVER_NAME);

    snprintf( info->vendor,
           DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
           PH_STBDFB_VENDOR_NAME );

    info->version.major = PH_STBDFB_VERSION_MAJOR;
    info->version.minor = PH_STBDFB_VERSION_MINOR;

    info->driver_data_size = 0;
    info->device_data_size = sizeof(phStbDFB_DeviceData_t);
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
}

/******************************************************************************/
static DFBResult
driver_init_driver( GraphicsDevice      *device,
                    GraphicsDeviceFuncs *funcs,
                    void                *driver_data,
                    void                *device_data,
                    CoreDFB             *core )
{
    int fbDev;
    char fbDevDeviceName[20];
    bool fbdevExists = true;
    bool found8335FbDev = false;
    int i = 0;

    /*
     * Init Driver is the only function called to initialise the driver in slave
     * instance of directfb, so we need to make sure that the debug is initialised
     * here.
     */
    init_debug();
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);
    /*
     * Store the Device data so that phStbDFB_GetLayerId can search the
     * layers for their surfaces.
     */
    gpphStbDFB_DeviceData = (phStbDFB_DeviceData_t*)device_data;
    phStbDFB_InitHWAccel(funcs);

    /* Check we can open the frmaebuffer device.  This only works if /dev/fb0 is the correct
       framebuffer.  On STB810 a custom ICTL was used to make sure we had found the correct FB
       device.  We may need to move to this in the future.*/
    while(fbdevExists && !found8335FbDev)
    {
        /*Make the device name /dev/fb0 /dev/fb1...etc*/
        sprintf(fbDevDeviceName, "/dev/fb%d", i++);

        /*open fbdev using specifed filename*/
        if ((fbDev = open(fbDevDeviceName, O_RDWR)) < 0)
        {
            D_ERROR("DirectFB/Graphics/STB225: Could not open %s\n", fbDevDeviceName);
            fbdevExists=false;
            continue;
        }

        /*We have found a valid framebuffer device and its ours hooray*/
        D_INFO("DirectFB/Graphics/STB225: %s is the NXP STB225 Framebuffer Device\n", fbDevDeviceName);
        found8335FbDev = true;

        /*Close the file descriptor*/
        close(fbDev);
    }
    /*Check we actually found a pc*/
    if(!fbdevExists)
    {
        D_ERROR("DirectFB/Graphics/STB225: Failed to find NXP STB225 FrameBuffer Driver exiting\n");
        return DFB_BUG;
    }

    /*Register the screen currently we register only one screen and that is Displaychain_main. */
    phStbDFB_ScreenRegister(device);

    /*Register the Framebuffer layer.*/
	phStbDFB_FBDevGfxLayerRegister(device);
    /*Register the Video layers.*/
	phStbDFB_VidLayerRegister();
    /*Register the LCD layer.*/
    phStbDFB_FBDevLCDLayerRegister(device);

    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
    return DFB_OK;
}

/******************************************************************************/
static DFBResult
driver_init_device( GraphicsDevice     *device,
                    GraphicsDeviceInfo *device_info,
                    void               *driver_data,
                    void               *device_data )
{
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);

    /* fill device info */
    snprintf( device_info->name,   DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,   PH_STBDFB_DEVICE_NAME );
    snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, PH_STBDFB_VENDOR_NAME );

    /* device limitations */
    device_info->limits.surface_byteoffset_alignment = 4; //32Bit aligned
    device_info->limits.surface_bytepitch_alignment  = 8; //32Bit aligned

    /* NAB: no "0" value in enum. */
    device_info->caps.flags    = 0;

    if (phStbDFB_IsHWAccelerated())
    {
        D_INFO("DirectFB/Graphics/STB225: Acceleration enabled!\n");
        device_info->caps.accel    = PH_STBDFB_SUPPORTED_DRAWINGFUNCTIONS |
                                     PH_STBDFB_SUPPORTED_BLITTINGFUNCTIONS;
        if (gphStbDFB_stretchSupported)
        {
            device_info->caps.accel |= PH_STBDFB_SUPPORTED_STRETCHFUNCTIONS;
        }
        device_info->caps.drawing  = PH_STBDFB_SUPPORTED_DRAWINGFLAGS;
        device_info->caps.blitting = PH_STBDFB_SUPPORTED_BLITTINGFLAGS;
    }
    else
    {
        D_INFO("DirectFB/Graphics/STB225: Acceleration disabled!\n");
        device_info->caps.accel    = DFXL_NONE;
        device_info->caps.drawing  = DSDRAW_NOFX;
        device_info->caps.blitting = DSBLIT_NOFX;
    }

    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
    return DFB_OK;
}

/******************************************************************************/
/* Close device is only called from dfb_gfx_shutdown which in the multi application world
   is only called when the last app exits so here is the place to clean all encoders.
 */
static void
driver_close_device( GraphicsDevice *device,
                     void           *driver_data,
                     void           *device_data )
{
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);

    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
}

/******************************************************************************/
/* Close driver is called by every application that leaves.  So in multi app as
   each on exits this gets called. */
static void
driver_close_driver( GraphicsDevice *device,
                     void           *driver_data )
{
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_ENTER, "%s", __FUNCTION__);
    phStbDFB_DeInitHwAccel();
    DBG_PRINT1(gphStbDFB_DbgUnit, DBG_INTERFACE_LEAVE, "%s", __FUNCTION__);
}

/******************************************************************************/
static void
init_debug()
{
    if (!gphStbDFB_debugInit)
    {
        DBG_REGISTER_MODULE(gphStbDFB_DbgUnit, "StbDFB");
        DBG_ENABLE_FLAGS(gphStbDFB_DbgUnit, DBG_WARNING);
        gphStbDFB_debugInit = true;
    }
}

void phStbDFB(void)
{
    directfb_STB225();
}
