/*
 * DANG_BEGIN_MODULE
 *
 * Description:
 *   This module contains everything necessary to set up the BIOS memory
 *   area (the segment 0x0040)
 * 
 * Maintainers: 
 *
 * DANG_END_MODULE
 *
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 */

#include "dosemu.h"
#include "base/bios.h"
#include "base/serial.h"
#include "base/lpt.h"
#include "base/mouse.h"

/*
 * BIOS Data Area memory map [note all offsets are in HEX]
 *
 * Addr   Size   Desc                           Handling module
 * 40:00  word   COM1 port address              serial.c
 * 40:02  word   COM2 port address              serial.c
 * 40:04  word   COM3 port address              serial.c
 * 40:06  word   COM4 port address              serial.c
 * 40:08  word   LPT1 port address              lpt.c
 * 40:0A  word   LPT2 port address              lpt.c
 * 40:0C  word   LPT3 port address              lpt.c
 * 40:0D  word   Extended BIOS Data Area (*)    [this module]
 * 40:10  word   Equipment list flags           [this module]
 * 40:12  byte   POST status
 * 40:13  word   Lower memory size in Kbytes    [this module]
 * 40:15  byte   Manufacturing test scratchpad
 * 40:16  byte   Manufacturing test scratchpad
 * 40:17  byte   Keyboard flag byte 0           keyb.c
 * 40:18  byte   Keyboard flag byte 1           keyb.c
 * 40:19  byte   Alt-nnn keypad workspace       keyb.c
 * 40:1A  word   Keyboard buffer head pointer   keyb.c
 * 40:1C  word   Keyboard buffer tail pointer   keyb.c
 * 40:1E 32bytes Keyboard buffer                keyb.c
 * 40:3E  byte   Drive recalibration status
 * 40:3F  byte   Diskette motor status
 * 40:40  byte   Motor shutoff counter
 * 40:41  byte   Status of last diskette int13
 * 40:42 7bytes  FDC controller status
 * 40:49  byte   Current video mode             video modules
 * 40:4A  word   Number of screen columns       video modules
 * 40:4C  word   Size of video regen buffer     video modules
 * 40:4E  word   Offset of current video page   video modules
 * 40:50 8words  Cursor pos of pages 1-8        video modules
 * 40:60  byte   Cursor end scan line           video modules
 * 40:61  byte   Cursor begin scan line         video modules
 * 40:62  byte   Active display page number     video modules
 * 40:63  word   Base port for CRT controller   video modules
 * 40:65  byte   CRT mode control reg value     video modules
 * 40:66  byte   CRT color palette mask setting video modules
 * 40:67  dword  Pointer to reset code
 * 40:6B  byte   Unexpected IRQ's               bios.S
 * 40:6C  dword  Timer ticks since midnight     bios_int.c
 * 40:70  byte   Timer counter overflow         bios_int.c
 * 40:71  byte   BIOS break flag                bios_int.c
 * 40:72  word   POST reset flag
 * 40:74  byte   Status of last hard disk oper.
 * 40:75  byte   Number of hard disks attached
 * 40:76  byte   XT fixed disk control byte
 * 40:77  byte   Port offset to cur. fixed disk
 * 40:78 3bytes  Timeout values for LPT1-LPT3
 * 40:7B  byte   Int 4B DMA support info
 * 40:7C 4bytes  Timeout values for COM1-COM4
 * 40:80  word   Keyboard buffer start offset   keyb.c
 * 40:82  word   Keyboard buffer end offset     keyb.c
 * 40:84  byte   Screen rows - 1                video modules
 * 40:85  word   Point height of char. matrix   video modules
 * 40:87  byte   Video mode options             video modules
 * 40:88  byte   EGA features switch            video modules
 * 40:89  byte   Video display data area        video modules
 * 40:8A  byte   Video DCC table index          video modules
 * 40:8B  byte   Last diskette rate selected
 * 40:8C  byte   Hard disk controller status
 * 40:8D  byte   Hard disk controller error
 * 40:8E  byte   Hard disk interrupt control
 * 40:8F  byte   Combination hdrive/floppy card
 * 40:90 4bytes  Drive 0,1,2,3 media state
 * 40:94  byte   Drive 0 track selected
 * 40:95  byte   Drive 1 track selected
 * 40:96  byte   Keyboard mode/type             keyb.c
 * 40:97  byte   Keyboard LED flags             keyb.c
 * 40:98  dword  Pointer to user wait complete
 * 40:9C  dword  User wait value (msecs)
 * 40:A0  byte   RTC wait function flag
 * 40:A1  byte   LANA DMA channel flags
 * 40:A2 2bytes  Status of LAN0,1
 * 40:A4  dword  Saved hdrive int vector
 * 40:A8  dword  Saved BIOS video pointer table
 * 40:AC 34bytes [reserved]                     ---
 * 40:CE  word   Number of days since last boot
 * 40:D0 32bytes [reserved]                     ---
 * 40:F0 16bytes [reserved for user]            ---
 * 50:00  byte   Print screen status byte       bios.S
 */

static Bit16u bios_config;

static void bios_setup_configuration(void)
{
  bios_config = 0;

  /* Configuration word:
   *   bit 0     = IPL diskette installed
   *   bit 1     = math coprocessor
   *   bit 2     = PS/2 pointing device installed
   *   bit 3     = unused
   *   bit 4-5   = initial video mode
   *   bit 6-7   = number of floppy drives installed - 1
   *   bit 8     = 0 if DMA present
   *   bit 9-11  = number of serial ports
   *   bit 12    = game adapter installed
   *   bit 13    = unused, internal modem on PS/2
   *   bit 14-15 = number of printer ports
   */

  if (config.mathco)
    bios_config |= 0x02;

  if ((mice->type == MOUSE_PS2) || mice->intdrv)
    bios_config |= 0x04;

  bios_config |= 0x20;                     /* start in COLOR video mode */
  bios_config |= (config.fdisks - 1) << 6;
  bios_config |= config.num_ser << 9;
  bios_config |= config.num_lpt << 15;
}

static void bios_ebda_reset(void)
{
  Bit16u  ebda_seg;
  Bit8u  *ebda_ptr;
/*
 * Reserve the top 1K of lower memory for the Enhanced Bios Data Area.
 * Basically, we don't do anything here, but it'll make DOS a little
 * happier.
 */
  ebda_seg = READ_WORD(bios_memory_size);
  ebda_ptr = (Bit8u *)((Bit32u)ebda_seg << 4);
  WRITE_WORD(bios_memory_size, ebda_seg - 1);

  MEMSET_DOS(ebda_ptr, 0, 1024);        /* Reset the EBDA */
  WRITE_BYTE(ebda_ptr, 0x01);           /* 1K of EBDA */
  /* bytes @ ebda_ptr+0x01-0x21 reserved */
  /* dword @ ebda_ptr+0x22      pointing device device driver entry point */
  /* byte  @ ebda_ptr+0x26      pointing device flag (byte 1) */
  /* byte  @ ebda_ptr+0x27      pointing device flag (byte 2) */
  /* bytes @ ebda_ptr+0x28-0x2F reserved */
}

void bios_mem_init(void)
{
}

void bios_mem_reset(void)
{
  bios_setup_configuration();

#if 0
  MEMSET_DOS(0x0400, 0, 0x0200);      /* clear the BIOS data segment */
#endif

  WRITE_WORD(bios_base_addr_com1, com[0].base_port);
  WRITE_WORD(bios_base_addr_com2, com[1].base_port);
  WRITE_WORD(bios_base_addr_com3, com[2].base_port);
  WRITE_WORD(bios_base_addr_com4, com[3].base_port);

  WRITE_WORD(bios_base_addr_lpt1, lpt[0].base_port);
  WRITE_WORD(bios_base_addr_lpt2, lpt[1].base_port);
  WRITE_WORD(bios_base_addr_lpt3, lpt[2].base_port);

  WRITE_WORD(bios_extended_bios,  0);
  WRITE_WORD(bios_configuration,  bios_config);
  WRITE_WORD(bios_memory_size,    config.mem_size);

  WRITE_WORD(bios_keyboard_state, 0);    /* no ctrl/shift/alt etc. pressed */
  WRITE_BYTE(bios_keyboard_leds,  0);     /* no keyboard led's set */
#if 0
  WRITE_WORD(bios_keyboard_token, ???);  /* 'storage for alt. keypad entry' */
#endif

  WRITE_WORD(bios_keyboard_buffer_head, 0x001E);
  WRITE_WORD(bios_keyboard_buffer_tail, 0x001E);

#if 0
  WRITE_BYTE(bios_drive_recalib_stat, ???);
  WRITE_BYTE(bios_drive_floppy_stat, ???);
  WRITE_BYTE(bios_motor_shutoff, ???);
  WRITE_BYTE(bios_disk_status, ???);

  /* bios_fdc_result_buffer */

  WRITE_BYTE(bios_video_mode, ???);
  WRITE_WORD(bios_screen_columns, ???);
  WRITE_WORD(bios_video_memory_used, ???);
  WRITE_WORD(bios_video_memory_addr, ???);

  for (i = 0; i < 8; i++) {
    WRITE_BYTE(bios_cursor_x_position(i), ???);
    WRITE_BYTE(bios_cursor_y_position(i), ???);
  }

  WRITE_WORD(bios_cursor_shape, ???);
  WRITE_BYTE(bios_cursor_last_line, ???);
  WRITE_BYTE(bios_cursor_first_line, ???);
  WRITE_BYTE(bios_current_screen_page, ???);
  WRITE_WORD(bios_video_port, ???);
  WRITE_BYTE(bios_vdu_control, ???);
  WRITE_WORD(bios_vdu_control_register, ???);

  WRITE_DWORD(bios_timer, ???);
  WRITE_BYTE(bios_24_hours_flag, 0);

  WRITE_BYTE(bios_keyboard_flags, ???);
#endif

  WRITE_WORD(bios_ctrl_alt_del_flag, 0);

#if 0
  WRITE_BYTE(bios_hdrive_stat, ???);
  WRITE_BYTE(bios_hdrive_count, ???);
  WRITE_BYTE(bios_xt_fdisk_ctrl, ???);
  WRITE_BYTE(bios_hdrive_port_off, ???);
  WRITE_BYTE(bios_lpt1_timeout, ???);
  WRITE_BYTE(bios_lpt2_timeout, ???);
  WRITE_BYTE(bios_lpt3_timeout, ???);
  WRITE_BYTE(bios_lpt4_timeout, ???);
  WRITE_BYTE(bios_com1_timeout, ???);
  WRITE_BYTE(bios_com2_timeout, ???);
  WRITE_BYTE(bios_com3_timeout, ???);
  WRITE_BYTE(bios_com4_timeout, ???);
#endif

  WRITE_WORD(bios_keyboard_buffer_start, 0x001E);
  WRITE_WORD(bios_keyboard_buffer_end,   0x003E);

#if 0
  WRITE_BYTE(bios_rows_on_screen_minus_1, ???);
  WRITE_WORD(bios_font_height, ???);

  WRITE_BYTE(bios_video_info_0, ???);
  WRITE_BYTE(bios_video_info_1, ???);
  WRITE_BYTE(bios_video_info_2, ???);
  WRITE_BYTE(bios_video_combo, ???);

  WRITE_BYTE(bios_floppy_readrate, ???);
  WRITE_BYTE(bios_hdisk_status, ???);
  WRITE_BYTE(bios_hdisk_error, ???);
  WRITE_BYTE(bios_hdisk_busy, ???);
  WRITE_BYTE(bios_combo_disk_card, ???);
  WRITE_BYTE(bios_media_state, ???);
  WRITE_BYTE(bios_floppy0_track, ???);
  WRITE_BYTE(bios_floppy1_track, ???);
#endif

  WRITE_WORD(bios_keyboard_flags2, 16);        /* 102 key keyboard */
  WRITE_DWORD(bios_usr_wait_flg_ptr, 0x00000000);
  WRITE_DWORD(bios_usr_wait_rtc, 0x00000000);
  WRITE_BYTE(bios_rtc_flag, 0);
  WRITE_BYTE(bios_lana_flags, 0);
  WRITE_BYTE(bios_lana_status0, 0);
  WRITE_BYTE(bios_lana_status1, 0);
  WRITE_DWORD(bios_hdisk_int_vec, 0x00000000);
  WRITE_DWORD(bios_video_saveptr, 0xf000f0a4);
  WRITE_WORD(bios_print_screen_flag, 0x00);

#if 0
  bios_ebda_reset();
#endif
}
