/*
[SCE CONFIDENTIAL]
$PSDocId$
                  Copyright (C) 2002-4 Sony Computer Entertainment America
                                                     All Rights Reserved
//  ------------------------------------------------------------------------

File: libezcnf.c

//  ------------------------------------------------------------------------
*/

#include <stdio.h>
#include <string.h>

#include <eekernel.h>
#include <sif.h>
#include <sifdev.h>
#include <sifrpc.h>

#include "../include/eznetcnf.h"
#include "internal.h"


/*  --------------------------------------------------------
 *  global and static variables
 *  --------------------------------------------------------
 */

    // RPC client data
static rpcRequest_t     m_rpcBuf __attribute__((aligned(64)));
static sceSifClientData m_rpcCd;

static int m_modId;
static int m_rpcRunning;


/*  --------------------------------------------------------
 *  PUBLIC library initialization and finalization
 *  --------------------------------------------------------
 */

/*
 *  initialize eznetcnf state, and bind to RPC service.
 *
 *  r = 0 if initialization succeeds.
 *  r < 0 if IOP service module is not resident.
 */
int
ezNetCnfInit()
{
    int err;

    /*
     *  bind to RPC server on IOP
     */
    m_modId = err = sceSifSearchModuleByName(kModName_ezNetCnf);
    if (m_modId < 0) {
        dprintf("%s module not found\n", kModName_ezNetCnf);
        m_rpcRunning = 0;
    } else {
        while (1) {
            if (0 > sceSifBindRpc(&m_rpcCd, kRPCId_ezNetCnf, 0)) {
                dprintf("sceSifBindRpc failed, retrying\n");
            }
            if (m_rpcCd.serve != 0) break;
            DelayThread(10 * 1000);
        }
        m_rpcRunning = 1;
    }

    // normalize err
    return (err < 0) ? err : 0;
}


/*
 *  exit and unload eznetcnf.irx.
 *
 *  r = 0 after unload succeeds.
 *  r < 0 if IOP service module fails to stop or unload.
 */
int
ezNetCnfExit()
{
    int err;

    // stop and unload IOP module
    if ( m_rpcRunning &&
         0 <= sceSifStopModule(m_modId, 0, NULL, &err) &&
         0 <= (err = sceSifUnloadModule(m_modId)) )
    {
        err = m_rpcRunning = 0;
    }

    return err;
}


/*  --------------------------------------------------------
 *  PUBLIC library interfaces
 *  --------------------------------------------------------
 */

/*
 *  given the path to a netdb database, count how many Combinations 
 *  are available.
 *
 *  r > 0   when there is at least one valid Combination,
 *  r = 0   when no Combinations exist at the netdb location,
 *  r < 0   when other netcnf.irx errors are detected.
 */
int
ezNetCnfGetCount(const char *netdb)
{
    rpcRequest_t *request = &m_rpcBuf;

    ASSERT_RPC(sizeof(rpcRequest_t));

    // pack RPC request
    strncpy(request->buf1, netdb, sizeof(request->buf1)-1);

    // call RPC
    sceSifCallRpc(&m_rpcCd, eCnfGetCount, 
                  0,
                  request, sizeof(rpcRequest_t),
                  request, sizeof(int),
                  NULL, NULL);

    dprintf("returned %d\n", request->args[0]);
    return request->args[0];
}


/*
 *  given the path to a netdb database, retrieve a list of Combinations 
 *  to the memory address specified at addr. this list contains all the 
 *  information needed to present to the user.
 *
 *  r > 0   when there is at least 1 valid Combination,
 *  r = 0   when there are no Combinations or no valid Combinations,
 *  r < 0   when other netcnf.irx errors are detected.
 */
int
ezNetCnfGetCombinationList(const char *netdb, int flags, ezNetCnfCombinationList_t *addr)
{
    rpcRequest_t *request = &m_rpcBuf;

    ASSERT_RPC( sizeof(rpcRequest_t) );
    ASSERT_DMA( addr, 64 );
    InvalidDCache( (void *)addr, (void *)((u_int)addr+sizeof(*addr)-1) );

    // pack RPC request
    request->args[0] = (u_int)addr;
    request->args[1] = flags;
    strncpy(request->buf1, netdb, sizeof(request->buf1)-1);

    // call RPC
    sceSifCallRpc(&m_rpcCd, eCnfGetCombinationList, 
                  0,
                  request, sizeof(rpcRequest_t),
                  request, sizeof(int),
                  NULL, NULL);

    dprintf("returned %d\n", request->args[0]);
    return request->args[0];
}


/*
 *  given the list of combinations and an ordinal number (1..N),
 *  return "CombinationN" -- REMEMBER to adjust zero-based indices.
 *
 *  r != NULL   for valid pList and valid number,
 *  r == NULL   for empty or invalid pList, or invalid number.
 */
ezNetCnfCombination_t *
ezNetCnfGetCombination(ezNetCnfCombinationList_t *pList, int number)
{
    // check for valid parameters
    if (pList == NULL || pList->listLength == 0) {
        dprintf("pList is empty\n");
        return NULL;
    }
    if (number < 1 || number > pList->listLength) {
        dprintf("invalid Combination number (%d)\n", number);
        return NULL;
    }

    return &pList->list[number - 1];
}


/*
 *  given a previously generated list of combination configurations,
 *  return the Combination designated as the "default" in netdb.
 *
 *  r != NULL   for valid pList,
 *  r == NULL   for empty or invalid pList.
 */
ezNetCnfCombination_t *
ezNetCnfGetDefault(ezNetCnfCombinationList_t *pList)
{
    // check for valid parameters
    if (pList == NULL || pList->listLength == 0) {
        dprintf("pList is empty\n");
        return NULL;
    }
    if (pList->defaultNumber < 1 || pList->defaultNumber > pList->listLength) {
        dprintf("invalid default Combination number (%d)\n", pList->defaultNumber);
        return NULL;
    }

    return &pList->list[pList->defaultNumber - 1];
}


/*
 *  given the netdb path and a designated Combination, read and convert
 *  the data to a sceNetcnfifData record at the specified memory address.
 *  this data will contain all essential configuration properties.
 *
 *  r = 0   for successfully loading Combination,
 *  r < 0   for error.
 */
int
ezNetCnfGetProperties(const char *netdb, 
                      const char *combinationName, 
                      sceNetcnfifData_t *addr)
{
    rpcRequest_t *request = &m_rpcBuf;

    ASSERT_RPC( sizeof(rpcRequest_t) );
    ASSERT_DMA( addr, 64 );
    InvalidDCache( (void *)addr, (void *)((u_int)addr+sizeof(*addr)-1) );

    // pack the RPC request structure
    request->args[0] = (u_int)addr;
    strncpy(request->buf1, netdb, sizeof(request->buf1)-1);
    strncpy(request->buf2, combinationName, sizeof(request->buf2)-1);

    // call RPC
    sceSifCallRpc(&m_rpcCd, eCnfGetProperties, 
                  0,
                  request, sizeof(rpcRequest_t),
                  request, sizeof(int),
                  NULL, NULL);

    dprintf("returned %d\n", request->args[0]);
    return request->args[0];
}

