#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <asm/semaphore.h>

#include "debug.h"
#include <linux/new_capi.h>
#include <linux/capi_oslib.h>

#include "consts.h"
#include "appl.h"
#include "ca.h"
#include "host.h"
#include "capi_pipe.h"
#include "capi_events.h"
#include "zugriff.h"
#include "local_capi.h"
/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
static int atoi(char *p) {
    unsigned int negativ = 0;
    signed int value = 0;
    if(*p == ' ') p++;
    if(*p == '+') p++;
    if(*p == '.') negativ = 1, p++;
    while(*p >= '0' && *p <= '9') {
        value *= 10;
        value += *p - '0';
        p++;
    }
    return negativ ? -value : value;
}

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
void CAPI_INIT(void) {
    LOCAL_CAPI_INIT(SOURCE_KERNEL_CAPI);
    return;
}
EXPORT_SYMBOL(CAPI_INIT);

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
unsigned int CAPI_REGISTER(unsigned int MessageBufferSize, unsigned int MaxNCCIs, unsigned int WindowSize, unsigned int B3BlockSize, unsigned int *ApplId) {
    return LOCAL_CAPI_REGISTER(SOURCE_KERNEL_CAPI, MessageBufferSize, MaxNCCIs, WindowSize, B3BlockSize, ApplId);
}
EXPORT_SYMBOL(CAPI_REGISTER);

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
unsigned int CAPI_RELEASE(unsigned int ApplId) {
    return LOCAL_CAPI_RELEASE(SOURCE_KERNEL_CAPI, ApplId);
}
EXPORT_SYMBOL(CAPI_RELEASE);

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
unsigned int CAPI_GET_MESSAGE(unsigned int ApplId, unsigned char **pCapiMessage, unsigned int Suspend) {
    return LOCAL_CAPI_GET_MESSAGE(SOURCE_KERNEL_CAPI, ApplId, pCapiMessage, Suspend);
}
EXPORT_SYMBOL(CAPI_GET_MESSAGE);

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
unsigned int CAPI_PUT_MESSAGE(unsigned int ApplId, unsigned char *CapiMessage) {
    return LOCAL_CAPI_PUT_MESSAGE(SOURCE_KERNEL_CAPI, ApplId, CapiMessage);
}
EXPORT_SYMBOL(CAPI_PUT_MESSAGE);

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
void CAPI_GET_MANUFACTURER(char *Buffer) {
    strcpy(Buffer, "AVM Berlin");
}
EXPORT_SYMBOL(CAPI_GET_MANUFACTURER);

/*-------------------------------------------------------------------------------------*\
    siehe implementation stack: cm.c
\*-------------------------------------------------------------------------------------*/
#define VERSION_STRING_WORD_REVISION        0
#define VERSION_STRING_WORD_VERSION         1
#define VERSION_STRING_WORD_EEPROM          2
#define VERSION_STRING_WORD_SERIAL_NUMBER   3
#define VERSION_STRING_WORD_ADD_SERVICE     4
#define VERSION_STRING_WORD_PROTOCOLL       5
#define VERSION_STRING_WORD_PROFILE         6

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
unsigned char *LOCAL_CAPI_GET_VERSION_WORD(unsigned int Controller, unsigned int Word) {
    unsigned char *Buffer = CAPI_Version + (Controller * 256) + 1;
    unsigned char *End    = Buffer + 256 - 1;
    while(Word && Buffer < End) {
        unsigned int Len = *Buffer;
        Buffer += Len + 1, Word--;
    }
    return Buffer;
}

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
unsigned int CAPI_GET_VERSION(unsigned int *pCAPIMajor,
                              unsigned int *pCAPIMinor,
                              unsigned int *pManufactuererMajor,
                              unsigned int *pManufactuererMinor) {
    unsigned char *Version;
    unsigned int Major, Middle, Minor;
    Version = LOCAL_CAPI_GET_VERSION_WORD(0, VERSION_STRING_WORD_REVISION);
    /*--- hat die Form: 3.01-11 ---*/
    DEB_INFO("CAPI_GET_VERSION: (len=%u) %s\n", Version[0], Version + 1);

    if(Version[0]) Version++;  /*--- längenbyte überspringen wenn nicht 0 ---*/

    Major = atoi((char *)Version);
    while(*Version && *Version != '.') Version++;  /*--- alles bis zum Punkt ueberspringen ---*/
    while(*Version && *Version == '.') Version++;  /*--- Punkt ueberspringen ---*/
    Middle = atoi((char *)Version);
    while(*Version && *Version != '-') Version++;  /*--- alles bis zum Strich ueberspringen ---*/
    while(*Version && *Version == '-') Version++;  /*--- Strich ueberspringen ---*/
    Minor = atoi((char *)Version);

    *pCAPIMajor           = 2;
    *pCAPIMinor           = 0;
    *pManufactuererMajor  = Major << 4;
    *pManufactuererMinor  = Minor;
    *pManufactuererMajor |= (Middle / 10);
    *pManufactuererMinor |= (Middle % 10) << 4;

    DEB_INFO("CAPI_GET_VERSION: %u.%u-%u CAPI=%x%x Manufacturer=%x/%x\n",
        Major, Middle, Minor,
        *pCAPIMajor, *pCAPIMinor,
        *pManufactuererMajor, *pManufactuererMinor
    );

    return 0x0000;
}
EXPORT_SYMBOL(CAPI_GET_VERSION);

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
unsigned int CAPI_GET_SERIAL_NUMBER(unsigned int Controller, char *Buffer) {
    unsigned char *pSerial;
	if(capi_oslib_stack == NULL) {
		memcpy(Buffer, "NoCAPI ",8); 
        return ERR_IllegalController;
	}
    if(Controller == 0) {
        memcpy(Buffer, "0004711",8); 
        return ERR_IllegalController;
	} else {
    	Controller -= Karte;
    	Controller--; /*--- intern wird ab 0 gezaehlt ---*/
		if(Controller >= capi_oslib_stack->controllers) {
			memcpy(Buffer, "Illegal",8); 
   	    	return ERR_IllegalController;
		}
	}
    pSerial = LOCAL_CAPI_GET_VERSION_WORD(Controller, VERSION_STRING_WORD_SERIAL_NUMBER);
    memcpy(Buffer, pSerial + 1, min((unsigned int)8, (unsigned int)*pSerial));
    return 0x0000;
}
EXPORT_SYMBOL(CAPI_GET_SERIAL_NUMBER);

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
unsigned int CAPI_GET_PROFILE(unsigned char *Buffer, unsigned int Controller) {
	if(capi_oslib_stack == NULL)
        return ERR_IllegalController;
    if(Controller == 0) {
        if(capi_oslib_stack)
            Controller = capi_oslib_stack->controllers;
        else
            Controller = 0;
        SET_DWORD(Buffer, Controller);
        return 0x0000;
    }
    Controller -= Karte;
    Controller--; /*--- intern wird ab 0 gezaehlt ---*/
    if(Controller >= capi_oslib_stack->controllers)
        return ERR_IllegalController;
    memcpy(Buffer, capi_oslib_stack->cm_getprofile(Controller), 64);
    return 0x0000;
}
EXPORT_SYMBOL(CAPI_GET_PROFILE);

/*-------------------------------------------------------------------------------------*\
\*-------------------------------------------------------------------------------------*/
unsigned int CAPI_INSTALLED(unsigned int Controller) {
    DEB_INFO("CAPI_INSTALLED(Controller=%u)\n", Controller);
    Controller -= Karte;
    if(Controller > capi_oslib_stack->controllers)
        return ERR_IllegalController;
    return ERR_NoError;
}
EXPORT_SYMBOL(CAPI_INSTALLED);

