/*
 * apm2.c
 *
 * Copyright 2004, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 */


#include"types.h"
#include"lib.h"
#include"segment.h"
#include"apm.h"


volatile FARCALL_ADDR apmfarCall;	/* Indirect address for APM far call. */
extern ushort apmVersion;
extern ushort apmFlag;
extern uint apmCodeSegBase;		/* Real mode segment base address. */
extern uint apmCode16SegBase;	/* Real mode segment base address. */
extern uint apmDataSegBase;		/* Real mode segment base address. */
extern uint apmOffset;
extern uint apmCodeSegLen;
extern uint apmCode16SegLen;
extern uint apmDataSegLen;


typedef struct{
	ushort ax;
	ushort bx;
	ushort cx;
	ushort dx;
	ushort si;
	ushort di;
}APM_FUNC_ARGS;


extern int invokeApmFunction(int fnum,APM_FUNC_ARGS *args);


/*****************************************************************************
 *
 * BIOS Functions
 *
 *****************************************************************************/

/*
 * GLOBAL
 * Get APM Driver Version.
 * return : driver version(BCD) or -1
 */
int getApmDriverVersion()
{
	APM_FUNC_ARGS args;


	if((apmFlag&APM_FLG_32MODE)==0)return APM_ERR_NOTPRESEN;

	args.bx=0;			/* APM BIOS device number. */
	args.cx=apmVersion;
	if(invokeApmFunction(APM_FUNC_DRVVRS,&args)==0)return args.ax;
	else return -1;
}


/*
 * GLOBAL
 * Set power state.
 * parameters : power flag
 * 0 or error coad
 */
int setPowerState(int flg)
{
	int rest;
	APM_FUNC_ARGS args;


	if((apmFlag&APM_FLG_32MODE)==0)return APM_ERR_NOTPRESEN;

	args.bx=APM_DEV_ALLDEV;			/* APM BIOS device number. */
	args.cx=flg;
	if((rest=invokeApmFunction(APM_FUNC_SETPWR,&args))==0)return 0;
	else return rest;
}


/*****************************************************************************
 *
 * 初期化
 *
 *****************************************************************************/

/*
 * GLOBAL
 * Init apm.
 */
void InitApm()
{
	if(apmFlag==0)return;		/* APM not supported. */

	/* APM version. */
	printk("APM : BIOS version %d.%d\n",apmVersion>>8,apmVersion&0xff);

	if((apmFlag&APM_FLG_32MODE)==0)return;	/* 32-bit protected mode interface not supported. */

	if(apmOffset==0)
		printk("APM 32bit mode interface connection error! error coad : %x\n",apmCodeSegBase>>8);

	/* APMコネクション用セグメントの設定。 */
	set_gdt(APM_CODE_DES,apmCodeSegBase<<4,apmCodeSegLen,TYPE_KERNEL_CODE);			/* Code segment. */
	set_gdt(APM_CODE16_DES,apmCode16SegBase<<4,apmCode16SegLen,TYPE_KERNEL_CODE16);	/* 16bit code segment. */
	set_gdt(APM_DATA_DES,apmDataSegBase<<4,apmDataSegLen,TYPE_KERNEL_DATA);			/* Data segment. */
	apmfarCall.des=APM_CODE_DES;
	apmfarCall.addr=apmOffset;
}
