/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation, using version 2 of the License.             */
/*                                                                           */
/* This program 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 General Public License for more details.                              */
/*                                                                           */
/* You should have received a copy of the GNU General Public License         */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307       */
/* USA.                                                                      */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phStbBootDsp_Kmodule.c
    @brief  Linux kernel module for phStbBootDsp component.

@b  Component:  phStbBootDsp.

*//*

Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20061130   batelaan    Initial
  2 20061130   batelaan    Beautify.
  3 20061205   batelaan    Crosscheck fixes.
                           Don't use hardcoded memory size (use prjconfig for memory setup).
  4 20061206   batelaan    Use ttyS1
  5 20061211   batelaan    Pass phStbNetDev.pool=... parameter to image.
                           Use local uboot_image.h file.
  6 20061218   batelaan    Crosscheck; rm slave option.
  7 20070103   batelaan    Port to little endian.
  8 20070103   batelaan    Remove /dev entry. Read uImage directly during module loading.
  9 20070110   batelaan    Ensure Dsp is running with the right endianness.
 10 20070112   steel       Update for 2.6.19 kernel
 11 20070129   barnish     gunzip uncompressed length initialised correctly
 12 20070711   batelaan    Enhanced portability.
 13 20070919   batelaan    Portability fix.
 14 20070921   batelaan    Use module_param_named.
 15 20080205   batelaan    Update file copyright/license text
 16 20080327   laird       Change to use firmware loading.
 17 20080410   batelaan    Use direct file reading so we can boot DSP earlier.
 18 20090121   batelaan    Update license.
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

#include <phStbBootDsp.h>
#include <phStbBootDsp_Internal.h>
#include <prjconfig.h>

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

#define THIS_MODULE_DESCRIPTION "DSP Boot Loader"
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(THIS_MODULE_DESCRIPTION);
MODULE_AUTHOR("NXP B.V.");

/******************************************************************
* FUNCTION PROTOTYPES                    [p]ph<Module>_<Word>+    *
*******************************************************************/

static int __init StbBootDsp_ModuleInit(void);
static void __exit StbBootDsp_ModuleExit(void);

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                   [p]ph<Module>_<Word>+_t  *
*******************************************************************/

/*******************************************************************
* EXPORTED DATA                 g[k|p|kp|pk|kpk]ph<Module>_<Word>+ *
********************************************************************/

module_init(StbBootDsp_ModuleInit);
module_exit(StbBootDsp_ModuleExit);

/*******************************************************************
* LOCAL DATA                                                       *
********************************************************************/

static Char *image   = PH_STBBOOTDSP_DFLT_LOADFILE;
module_param(image, charp, S_IRUGO);
MODULE_PARM_DESC(image, "Specify the DSP image to use when booting. Default is: " PH_STBBOOTDSP_DFLT_LOADFILE);

static Char *cmdline   = PH_STBBOOTDSP_DFLT_CMDLINE;
module_param(cmdline, charp, S_IRUGO);
MODULE_PARM_DESC(cmdline, "Set the commandline used to boot the DSP. Default is: " PH_STBBOOTDSP_DFLT_CMDLINE);

#if PH_STBBOOTDSP_VERBOSE
module_param_named(verbose, gphStbBootDsp_Verbose, bool, S_IRUGO);
MODULE_PARM_DESC(verbose, "Enable verbose debug output.");
#endif

/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          tm[<layer>]<Module>[_<Word>+] for exported functions*
********************************************************************************/

int phStbBootDsp_ReadImage(const char *file)
{
    int st = -EIO;
    struct file *filp = NULL;
    ssize_t len;
    mm_segment_t saved_addr_limit;
    loff_t pos;

    /* This workaround (calling set_fs(KERNEL_DS)) prevent the memory access checks
       that normally would prevent kernel space code calling 'user-space' functions,
       such as open, read, write, close.
    */
    saved_addr_limit = get_fs();
    set_fs(KERNEL_DS);

    filp = filp_open(file, O_RDONLY, 0);
    if (IS_ERR(filp))
    {
        st = PTR_ERR(filp);
        printk(KERN_ERR "phStbBootDsp: error %d opening %s\n", st, file);
        goto DEPARTURES;
    }

    /* First we store the header somewhere else. */
    pos = filp->f_pos;
    len = vfs_read(filp, (char __user *)&phStbBootDsp_UImageHeader, sizeof(phStbBootDsp_UImageHeader), &pos);
    filp->f_pos = pos; // update file position after write. See sys_read() implementation.
    if (len != (ssize_t)sizeof(phStbBootDsp_UImageHeader))
    {
        /* Propagate error code (only negative value is a proper errno. */
        if (len < 0)
        {
            st = len;
        }
        printk(KERN_ERR "phStbBootDsp: read error %d %s\n", len, file);
        goto DEPARTURES;
    }

    st = phStbBootDsp_ProcessImageHeader();
    if (st != 0)
    {
        goto DEPARTURES;
    }

    /* Read 1 more byte than phStbBootDsp_UImageHeader.ih_size, but we expect to read exactly
       phStbBootDsp_UImageHeader.ih_size. This is a file size correctness check. */
    len = vfs_read(filp, (char __user *)phStbBootDsp_ImageTmpLoad, phStbBootDsp_UImageHeader.ih_size + 1, &pos);
    if (len != phStbBootDsp_UImageHeader.ih_size)
    {
        printk(KERN_ERR "phStbBootDsp: incorrect length of %s\n", file);
        st = -EIO;
        goto DEPARTURES;
    }
    phStbBootDsp_ImageLen = (uint32_t)len;

    st = 0;

  DEPARTURES:
    if ((filp != NULL) && !IS_ERR(filp))
    {
        filp_close(filp, current->files);
    }
    set_fs(saved_addr_limit);

    return st;
}

/******************************************************************************/
/** Module Creation function.

    @retval int 0 if module initialised successfully.
*/
static Int __init StbBootDsp_ModuleInit(void)
{
    Int result;

    printk("%s (%s-%s)\n", THIS_MODULE_DESCRIPTION, __DATE__, __TIME__);

    result = phStbBootDsp_BootDspFile(image, cmdline);
    if (result != 0)
    {
        goto ERROR_RETURN;
    }
    return 0;

  ERROR_RETURN:
    printk(KERN_ERR "%s (%s-%s) => %d\n", THIS_MODULE_DESCRIPTION, __DATE__, __TIME__, result);
    return result;
}

/******************************************************************************/
/** Module exit function.
    - de-init the module.
*/
static void __exit StbBootDsp_ModuleExit(void)
{
}

/******************************************************************************/
