Fixed building for new GUS MAX.
Updated copyright dates etc.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Instruction timing for i486-class.
|
||||
*
|
||||
* Version: @(#)codegen_timing_486.c 1.0.1 2018/02/14
|
||||
* Version: @(#)codegen_timing_486.c 1.0.2 2018/12/24
|
||||
*
|
||||
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -319,24 +319,24 @@ static INLINE int COUNT(int *c, int op_32)
|
||||
return *c;
|
||||
}
|
||||
|
||||
void codegen_timing_486_block_start()
|
||||
static void codegen_timing_486_block_start(void)
|
||||
{
|
||||
regmask_modified = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_486_start()
|
||||
static void codegen_timing_486_start(void)
|
||||
{
|
||||
timing_count = 0;
|
||||
last_prefix = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
static void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
{
|
||||
timing_count += COUNT(opcode_timings[prefix], 0);
|
||||
last_prefix = prefix;
|
||||
}
|
||||
|
||||
void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
static void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
{
|
||||
int **timings;
|
||||
uint64_t *deps;
|
||||
@@ -442,7 +442,7 @@ void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8);
|
||||
}
|
||||
|
||||
void codegen_timing_486_block_end()
|
||||
static void codegen_timing_486_block_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* - PMMX decode queue
|
||||
* - MMX latencies
|
||||
*
|
||||
* Version: @(#)codegen_timing_pentium.c 1.0.3 2018/09/04
|
||||
* Version: @(#)codegen_timing_pentium.c 1.0.4 2018/12/24
|
||||
*
|
||||
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -975,20 +975,20 @@ static INLINE int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat
|
||||
}
|
||||
|
||||
|
||||
void codegen_timing_pentium_block_start(void)
|
||||
static void codegen_timing_pentium_block_start(void)
|
||||
{
|
||||
u_pipe_full = decode_delay = decode_delay_offset = 0;
|
||||
}
|
||||
|
||||
|
||||
void codegen_timing_pentium_start(void)
|
||||
static void codegen_timing_pentium_start(void)
|
||||
{
|
||||
last_prefix = 0;
|
||||
prefixes = 0;
|
||||
}
|
||||
|
||||
|
||||
void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
static void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
{
|
||||
prefixes++;
|
||||
if ((prefix & 0xf8) == 0xd8)
|
||||
@@ -1122,7 +1122,7 @@ static void codegen_instruction(const uint64_t *timings, uint64_t *deps, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
static void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
{
|
||||
const uint64_t *timings;
|
||||
uint64_t *deps;
|
||||
@@ -1346,7 +1346,7 @@ nopair:
|
||||
addr_regmask = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_pentium_block_end()
|
||||
static void codegen_timing_pentium_block_end(void)
|
||||
{
|
||||
if (u_pipe_full)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Code generation timing for IDT WinChip processors.
|
||||
*
|
||||
* Version: @(#)codegen_timing_winchip.c 1.0.1 2018/02/14
|
||||
* Version: @(#)codegen_timing_winchip.c 1.0.2 2018/12/24
|
||||
*
|
||||
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -51,7 +51,7 @@
|
||||
#define CYCLES(c) (int *)c
|
||||
#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8))
|
||||
|
||||
static int *opcode_timings[256] =
|
||||
static const int *opcode_timings[256] =
|
||||
{
|
||||
/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL,
|
||||
/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3),
|
||||
@@ -74,7 +74,7 @@ static int *opcode_timings[256] =
|
||||
/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL
|
||||
};
|
||||
|
||||
static int *opcode_timings_mod3[256] =
|
||||
static const int *opcode_timings_mod3[256] =
|
||||
{
|
||||
/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL,
|
||||
/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3),
|
||||
@@ -97,7 +97,7 @@ static int *opcode_timings_mod3[256] =
|
||||
/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL
|
||||
};
|
||||
|
||||
static int *opcode_timings_0f[256] =
|
||||
static const int *opcode_timings_0f[256] =
|
||||
{
|
||||
/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
@@ -119,7 +119,7 @@ static int *opcode_timings_0f[256] =
|
||||
/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm,
|
||||
/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL,
|
||||
};
|
||||
static int *opcode_timings_0f_mod3[256] =
|
||||
static const int *opcode_timings_0f_mod3[256] =
|
||||
{
|
||||
/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
@@ -142,57 +142,57 @@ static int *opcode_timings_0f_mod3[256] =
|
||||
/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL,
|
||||
};
|
||||
|
||||
static int *opcode_timings_shift[8] =
|
||||
static const int *opcode_timings_shift[8] =
|
||||
{
|
||||
CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7)
|
||||
};
|
||||
static int *opcode_timings_shift_mod3[8] =
|
||||
static const int *opcode_timings_shift_mod3[8] =
|
||||
{
|
||||
CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3)
|
||||
};
|
||||
|
||||
static int *opcode_timings_f6[8] =
|
||||
static const int *opcode_timings_f6[8] =
|
||||
{
|
||||
&timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19)
|
||||
};
|
||||
static int *opcode_timings_f6_mod3[8] =
|
||||
static const int *opcode_timings_f6_mod3[8] =
|
||||
{
|
||||
&timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19)
|
||||
};
|
||||
static int *opcode_timings_f7[8] =
|
||||
static const int *opcode_timings_f7[8] =
|
||||
{
|
||||
&timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43)
|
||||
};
|
||||
static int *opcode_timings_f7_mod3[8] =
|
||||
static const int *opcode_timings_f7_mod3[8] =
|
||||
{
|
||||
&timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43)
|
||||
};
|
||||
static int *opcode_timings_ff[8] =
|
||||
static const int *opcode_timings_ff[8] =
|
||||
{
|
||||
&timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL
|
||||
};
|
||||
static int *opcode_timings_ff_mod3[8] =
|
||||
static const int *opcode_timings_ff_mod3[8] =
|
||||
{
|
||||
&timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL
|
||||
};
|
||||
|
||||
static int *opcode_timings_d8[8] =
|
||||
static const int *opcode_timings_d8[8] =
|
||||
{
|
||||
/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/
|
||||
CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
|
||||
};
|
||||
static int *opcode_timings_d8_mod3[8] =
|
||||
static const int *opcode_timings_d8_mod3[8] =
|
||||
{
|
||||
/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/
|
||||
CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
|
||||
};
|
||||
|
||||
static int *opcode_timings_d9[8] =
|
||||
static const int *opcode_timings_d9[8] =
|
||||
{
|
||||
/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/
|
||||
CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3)
|
||||
};
|
||||
static int *opcode_timings_d9_mod3[64] =
|
||||
static const int *opcode_timings_d9_mod3[64] =
|
||||
{
|
||||
/*FLD*/
|
||||
CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
|
||||
@@ -212,23 +212,23 @@ static int *opcode_timings_d9_mod3[64] =
|
||||
CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474)
|
||||
};
|
||||
|
||||
static int *opcode_timings_da[8] =
|
||||
static const int *opcode_timings_da[8] =
|
||||
{
|
||||
/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/
|
||||
CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
|
||||
};
|
||||
static int *opcode_timings_da_mod3[8] =
|
||||
static const int *opcode_timings_da_mod3[8] =
|
||||
{
|
||||
NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
static int *opcode_timings_db[8] =
|
||||
static const int *opcode_timings_db[8] =
|
||||
{
|
||||
/* FLDil FSTil FSTPil FLDe FSTPe*/
|
||||
CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8)
|
||||
};
|
||||
static int *opcode_timings_db_mod3[64] =
|
||||
static const int *opcode_timings_db_mod3[64] =
|
||||
{
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
@@ -241,63 +241,63 @@ static int *opcode_timings_db_mod3[64] =
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
};
|
||||
|
||||
static int *opcode_timings_dc[8] =
|
||||
static const int *opcode_timings_dc[8] =
|
||||
{
|
||||
/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/
|
||||
CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74)
|
||||
};
|
||||
static int *opcode_timings_dc_mod3[8] =
|
||||
static const int *opcode_timings_dc_mod3[8] =
|
||||
{
|
||||
/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/
|
||||
CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
|
||||
};
|
||||
|
||||
static int *opcode_timings_dd[8] =
|
||||
static const int *opcode_timings_dd[8] =
|
||||
{
|
||||
/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/
|
||||
CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5)
|
||||
};
|
||||
static int *opcode_timings_dd_mod3[8] =
|
||||
static const int *opcode_timings_dd_mod3[8] =
|
||||
{
|
||||
/* FFFREE FST FSTP FUCOM FUCOMP*/
|
||||
CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL
|
||||
};
|
||||
|
||||
static int *opcode_timings_de[8] =
|
||||
static const int *opcode_timings_de[8] =
|
||||
{
|
||||
/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/
|
||||
CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
|
||||
};
|
||||
static int *opcode_timings_de_mod3[8] =
|
||||
static const int *opcode_timings_de_mod3[8] =
|
||||
{
|
||||
/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/
|
||||
CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
|
||||
};
|
||||
|
||||
static int *opcode_timings_df[8] =
|
||||
static const int *opcode_timings_df[8] =
|
||||
{
|
||||
/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/
|
||||
CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8)
|
||||
};
|
||||
static int *opcode_timings_df_mod3[8] =
|
||||
static const int *opcode_timings_df_mod3[8] =
|
||||
{
|
||||
/* FFREE FST FSTP FUCOM FUCOMP*/
|
||||
CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL
|
||||
};
|
||||
|
||||
static int *opcode_timings_8x[8] =
|
||||
static const int *opcode_timings_8x[8] =
|
||||
{
|
||||
&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
|
||||
};
|
||||
static int *opcode_timings_8x_mod3[8] =
|
||||
static const int *opcode_timings_8x_mod3[8] =
|
||||
{
|
||||
&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
|
||||
};
|
||||
static int *opcode_timings_81[8] =
|
||||
static const int *opcode_timings_81[8] =
|
||||
{
|
||||
&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
|
||||
};
|
||||
static int *opcode_timings_81_mod3[8] =
|
||||
static const int *opcode_timings_81_mod3[8] =
|
||||
{
|
||||
&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
|
||||
};
|
||||
@@ -306,7 +306,7 @@ static int timing_count;
|
||||
static uint8_t last_prefix;
|
||||
static uint32_t regmask_modified;
|
||||
|
||||
static INLINE int COUNT(int *c, int op_32)
|
||||
static INLINE int COUNT(const int *c, int op_32)
|
||||
{
|
||||
if ((uintptr_t)c <= 10000)
|
||||
return (int)(uintptr_t)c;
|
||||
@@ -319,26 +319,26 @@ static INLINE int COUNT(int *c, int op_32)
|
||||
return *c;
|
||||
}
|
||||
|
||||
void codegen_timing_winchip_block_start()
|
||||
static void codegen_timing_winchip_block_start(void)
|
||||
{
|
||||
regmask_modified = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_winchip_start()
|
||||
static void codegen_timing_winchip_start(void)
|
||||
{
|
||||
timing_count = 0;
|
||||
last_prefix = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
static void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
{
|
||||
timing_count += COUNT(opcode_timings[prefix], 0);
|
||||
last_prefix = prefix;
|
||||
}
|
||||
|
||||
void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
static void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
{
|
||||
int **timings;
|
||||
const int **timings;
|
||||
uint64_t *deps;
|
||||
int mod3 = ((fetchdat & 0xc0) == 0xc0);
|
||||
int bit8 = !(opcode & 1);
|
||||
@@ -442,7 +442,7 @@ void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8);
|
||||
}
|
||||
|
||||
void codegen_timing_winchip_block_end()
|
||||
static void codegen_timing_winchip_block_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,334 +1,360 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of Cirrus Logic Crystal 423x sound devices.
|
||||
*
|
||||
* Version: @(#)snd_cs423x.c 1.0.0 2018/11/27
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
#define dbglog sound_card_log
|
||||
#include "../../emu.h"
|
||||
#include "../../io.h"
|
||||
#include "../../device.h"
|
||||
#include "../../timer.h"
|
||||
#include "../system/dma.h"
|
||||
#include "../system/pic.h"
|
||||
#include "sound.h"
|
||||
#include "snd_cs423x.h"
|
||||
|
||||
#define CS4231 0x80
|
||||
#define CS4231A 0xa0
|
||||
#define CS4232 0xa2
|
||||
#define CS4232A 0xb2
|
||||
#define CS4236 0x83
|
||||
#define CS4236B 0x03
|
||||
|
||||
|
||||
static int cs423x_vols[64];
|
||||
|
||||
void cs423x_setirq(cs423x_t *cs423x, int irq_ch)
|
||||
{
|
||||
cs423x->irq = irq_ch;
|
||||
}
|
||||
|
||||
void cs423x_setdma(cs423x_t *cs423x, int dma_ch)
|
||||
{
|
||||
cs423x->dma = dma_ch;
|
||||
}
|
||||
|
||||
uint8_t cs423x_read(uint16_t addr, void *p)
|
||||
{
|
||||
cs423x_t *cs423x = (cs423x_t *)p;
|
||||
uint8_t temp = 0xff;
|
||||
|
||||
if (cs423x->initb)
|
||||
return 0x80;
|
||||
|
||||
switch (addr & 3)
|
||||
{
|
||||
case 0: /*Index*/
|
||||
if (cs423x->mode2)
|
||||
temp = cs423x->index | cs423x->trd | cs423x->mce | cs423x->ia4 | cs423x->initb;
|
||||
else
|
||||
temp = cs423x->index | cs423x->trd | cs423x->mce | cs423x->initb;
|
||||
break;
|
||||
case 1:
|
||||
temp = cs423x->regs[cs423x->index];
|
||||
if (cs423x->index == 0x0b) {
|
||||
temp ^= 0x20;
|
||||
cs423x->regs[cs423x->index] = temp;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
temp = cs423x->status;
|
||||
break;
|
||||
case 3: // Todo Capture I/O read
|
||||
break;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
void cs423x_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
cs423x_t *cs423x = (cs423x_t *)p;
|
||||
double freq;
|
||||
|
||||
switch (addr & 3)
|
||||
{
|
||||
case 0: /*Index*/
|
||||
cs423x->index = val & (cs423x->mode2 ? 0x1F : 0x0F);
|
||||
cs423x->trd = val & 0x20;
|
||||
cs423x->mce = val & 0x40;
|
||||
cs423x->ia4 = val & 0x10;
|
||||
cs423x->initb = val & 0x80;
|
||||
break;
|
||||
case 1:
|
||||
switch (cs423x->index)
|
||||
{
|
||||
case 8:
|
||||
freq = (double)((val & 1) ? 16934400LL : 24576000LL);
|
||||
switch ((val >> 1) & 7)
|
||||
{
|
||||
case 0: freq /= 3072; break;
|
||||
case 1: freq /= 1536; break;
|
||||
case 2: freq /= 896; break;
|
||||
case 3: freq /= 768; break;
|
||||
case 4: freq /= 448; break;
|
||||
case 5: freq /= 384; break;
|
||||
case 6: freq /= 512; break;
|
||||
case 7: freq /= 2560; break;
|
||||
}
|
||||
cs423x->freq = (int64_t)freq;
|
||||
cs423x->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)cs423x->freq));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
cs423x->enable = ((val & 0x41) == 0x01);
|
||||
if (!cs423x->enable)
|
||||
cs423x->out_l = cs423x->out_r = 0;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
break;
|
||||
|
||||
case 12:
|
||||
val |= 0x8a;
|
||||
cs423x->mode2 = (val >> 6) & 1;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
cs423x->count = cs423x->regs[15] | (val << 8);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
if (!(val & 0x70))
|
||||
cs423x->status &= 0xfe;
|
||||
break;
|
||||
|
||||
case 25:
|
||||
break;
|
||||
}
|
||||
cs423x->regs[cs423x->index] = val;
|
||||
break;
|
||||
case 2:
|
||||
cs423x->status &= 0xfe;
|
||||
break;
|
||||
case 3: // Todo Playback I/O Write
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cs423x_speed_changed(cs423x_t *cs423x)
|
||||
{
|
||||
cs423x->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)cs423x->freq));
|
||||
}
|
||||
|
||||
void cs423x_update(cs423x_t *cs423x)
|
||||
{
|
||||
for (; cs423x->pos < sound_pos_global; cs423x->pos++)
|
||||
{
|
||||
cs423x->buffer[cs423x->pos * 2] = cs423x->out_l;
|
||||
cs423x->buffer[cs423x->pos * 2 + 1] = cs423x->out_r;
|
||||
}
|
||||
}
|
||||
|
||||
static void cs423x_poll(void *p)
|
||||
{
|
||||
cs423x_t *cs423x = (cs423x_t *)p;
|
||||
|
||||
if (cs423x->timer_latch)
|
||||
cs423x->timer_count += cs423x->timer_latch;
|
||||
else
|
||||
cs423x->timer_count = TIMER_USEC;
|
||||
|
||||
cs423x_update(cs423x);
|
||||
|
||||
if (cs423x->enable) {
|
||||
int32_t temp;
|
||||
|
||||
if (!(cs423x->mode2)) {
|
||||
switch (cs423x->regs[8] & 0x70)
|
||||
{
|
||||
case 0x00: /*Mono, 8-bit PCM*/
|
||||
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x10: /*Stereo, 8-bit PCM*/
|
||||
cs423x->out_l = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x40: /*Mono, 16-bit PCM*/
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0x50: /*Stereo, 16-bit PCM*/
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_l = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (cs423x->regs[8] & 0xf0)
|
||||
{
|
||||
case 0x00: /*Mono, 8-bit PCM*/
|
||||
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x10: /*Stereo, 8-bit PCM*/
|
||||
cs423x->out_l = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x40: /*Mono, 16-bit PCM*/
|
||||
case 0xc0: /*Mono, 16-bit PCM Big-Endian should not happen on x86*/
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0x50: /*Stereo, 16-bit PCM*/
|
||||
case 0xd0: /*Stereo, 16-bit PCM Big-Endian. Should not happen on x86*/
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_l = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
temp = dma_channel_read(cs423x->dma);
|
||||
cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0xa0: /*TODO Mono, ADPCM, 4-bit*/
|
||||
case 0xb0: /*TODO Stereo, ADPCM, 4-bit*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cs423x->regs[6] & 0x80) // Mute Left-Channel
|
||||
cs423x->out_l = 0;
|
||||
else
|
||||
cs423x->out_l = (cs423x->out_l * cs423x_vols[cs423x->regs[6] & 0x3f]) >> 16;
|
||||
|
||||
if (cs423x->regs[7] & 0x80) // Mute Right-Channel
|
||||
cs423x->out_r = 0;
|
||||
else
|
||||
cs423x->out_r = (cs423x->out_r * cs423x_vols[cs423x->regs[7] & 0x3f]) >> 16;
|
||||
|
||||
if (cs423x->regs[26] & 0x40) // Mono Output Mute
|
||||
cs423x->out_l = cs423x->out_r = 0;
|
||||
|
||||
if (cs423x->count < 0) {
|
||||
cs423x->count = cs423x->regs[15] | (cs423x->regs[14] << 8);
|
||||
if (!(cs423x->status & 0x01)) {
|
||||
cs423x->status |= 0x01;
|
||||
if (cs423x->regs[10] & 2)
|
||||
picint(1 << cs423x->irq);
|
||||
}
|
||||
}
|
||||
cs423x->count--;
|
||||
}
|
||||
else {
|
||||
cs423x->out_l = cs423x->out_r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cs423x_init(cs423x_t *cs423x)
|
||||
{
|
||||
int c;
|
||||
double attenuation;
|
||||
|
||||
cs423x->enable = 0;
|
||||
|
||||
cs423x->status = 0xcc;
|
||||
cs423x->index = cs423x->trd = 0;
|
||||
cs423x->mce = 0x40;
|
||||
cs423x->initb = 0;
|
||||
cs423x->mode2 = 0;
|
||||
|
||||
cs423x->regs[0] = cs423x->regs[1] = 0;
|
||||
cs423x->regs[2] = cs423x->regs[3] = 0x88;
|
||||
cs423x->regs[4] = cs423x->regs[5] = 0x88;
|
||||
cs423x->regs[6] = cs423x->regs[7] = 0x80;
|
||||
cs423x->regs[8] = 0;
|
||||
cs423x->regs[9] = 0x08;
|
||||
cs423x->regs[10] = cs423x->regs[11] = 0;
|
||||
cs423x->regs[12] = 0x8a;
|
||||
cs423x->regs[13] = 0;
|
||||
cs423x->regs[14] = cs423x->regs[15] = 0;
|
||||
cs423x->regs[16] = cs423x->regs[17] = 0;
|
||||
cs423x->regs[18] = cs423x->regs[19] = 0x88;
|
||||
cs423x->regs[22] = 0x80;
|
||||
cs423x->regs[24] = 0;
|
||||
cs423x->regs[25] = CS4231; //CS4231 for GUS MAX
|
||||
cs423x->regs[26] = 0x80;
|
||||
cs423x->regs[29] = 0x80;
|
||||
|
||||
cs423x->out_l = 0;
|
||||
cs423x->out_r = 0;
|
||||
|
||||
for (c = 0; c < 64; c++) // DAC and Loopback attenuation
|
||||
{
|
||||
attenuation = 0.0;
|
||||
if (c & 0x01) attenuation -= 1.5;
|
||||
if (c & 0x02) attenuation -= 3.0;
|
||||
if (c & 0x04) attenuation -= 6.0;
|
||||
if (c & 0x08) attenuation -= 12.0;
|
||||
if (c & 0x10) attenuation -= 24.0;
|
||||
if (c & 0x20) attenuation -= 48.0;
|
||||
|
||||
attenuation = pow(10, attenuation / 10);
|
||||
cs423x_vols[c] = (int)(attenuation * 65536);
|
||||
}
|
||||
timer_add(cs423x_poll, &cs423x->timer_count, &cs423x->enable, cs423x);
|
||||
}
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of Cirrus Logic Crystal 423x sound devices.
|
||||
*
|
||||
* Version: @(#)snd_cs423x.c 1.0.1 2019/01/13
|
||||
*
|
||||
* Authors: Altheos, <altheos@varcem.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018,2019 Altheos.
|
||||
* Copyright 2018,2019 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
#define dbglog sound_card_log
|
||||
#include "../../emu.h"
|
||||
#include "../../io.h"
|
||||
#include "../../device.h"
|
||||
#include "../../timer.h"
|
||||
#include "../system/dma.h"
|
||||
#include "../system/pic.h"
|
||||
#include "sound.h"
|
||||
#include "snd_cs423x.h"
|
||||
|
||||
|
||||
#define CS4231 0x80
|
||||
#define CS4231A 0xa0
|
||||
#define CS4232 0xa2
|
||||
#define CS4232A 0xb2
|
||||
#define CS4236 0x83
|
||||
#define CS4236B 0x03
|
||||
|
||||
|
||||
static int cs423x_vols[64];
|
||||
|
||||
|
||||
void
|
||||
cs423x_setirq(cs423x_t *dev, int irq_ch)
|
||||
{
|
||||
dev->irq = irq_ch;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cs423x_setdma(cs423x_t *dev, int dma_ch)
|
||||
{
|
||||
dev->dma = dma_ch;
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
cs423x_read(uint16_t addr, void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (dev->initb)
|
||||
return 0x80;
|
||||
|
||||
switch (addr & 3) {
|
||||
case 0: /*Index*/
|
||||
if (dev->mode2)
|
||||
ret = dev->indx | dev->trd | dev->mce | dev->ia4 | dev->initb;
|
||||
else
|
||||
ret = dev->indx | dev->trd | dev->mce | dev->initb;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ret = dev->regs[dev->indx];
|
||||
if (dev->indx == 0x0b) {
|
||||
ret ^= 0x20;
|
||||
dev->regs[dev->indx] = ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ret = dev->status;
|
||||
break;
|
||||
|
||||
case 3: // Todo Capture I/O read
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *)priv;
|
||||
double freq;
|
||||
|
||||
switch (addr & 3) {
|
||||
case 0: /*Index*/
|
||||
dev->indx = val & (dev->mode2 ? 0x1f : 0x0f);
|
||||
dev->trd = val & 0x20;
|
||||
dev->mce = val & 0x40;
|
||||
dev->ia4 = val & 0x10;
|
||||
dev->initb = val & 0x80;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (dev->indx) {
|
||||
case 8:
|
||||
freq = (double)((val & 1) ? 16934400LL : 24576000LL);
|
||||
switch ((val >> 1) & 7) {
|
||||
case 0: freq /= 3072; break;
|
||||
case 1: freq /= 1536; break;
|
||||
case 2: freq /= 896; break;
|
||||
case 3: freq /= 768; break;
|
||||
case 4: freq /= 448; break;
|
||||
case 5: freq /= 384; break;
|
||||
case 6: freq /= 512; break;
|
||||
case 7: freq /= 2560; break;
|
||||
}
|
||||
dev->freq = (int64_t)freq;
|
||||
dev->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)dev->freq));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
dev->enable = ((val & 0x41) == 0x01);
|
||||
if (! dev->enable)
|
||||
dev->out_l = dev->out_r = 0;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
break;
|
||||
|
||||
case 12:
|
||||
val |= 0x8a;
|
||||
dev->mode2 = (val >> 6) & 1;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
dev->count = dev->regs[15] | (val << 8);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
if (! (val & 0x70))
|
||||
dev->status &= 0xfe;
|
||||
break;
|
||||
|
||||
case 25:
|
||||
break;
|
||||
}
|
||||
dev->regs[dev->indx] = val;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
dev->status &= 0xfe;
|
||||
break;
|
||||
|
||||
case 3: // Todo Playback I/O Write
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cs423x_update(cs423x_t *dev)
|
||||
{
|
||||
for (; dev->pos < sound_pos_global; dev->pos++) {
|
||||
dev->buffer[dev->pos * 2] = dev->out_l;
|
||||
dev->buffer[dev->pos * 2 + 1] = dev->out_r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cs423x_poll(void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *)priv;
|
||||
int32_t temp;
|
||||
|
||||
if (dev->timer_latch)
|
||||
dev->timer_count += dev->timer_latch;
|
||||
else
|
||||
dev->timer_count = TIMER_USEC;
|
||||
|
||||
cs423x_update(dev);
|
||||
|
||||
if (! dev->enable) {
|
||||
dev->out_l = dev->out_r = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (! (dev->mode2)) switch (dev->regs[8] & 0x70) {
|
||||
case 0x00: /*Mono, 8-bit PCM*/
|
||||
dev->out_l = dev->out_r = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x10: /*Stereo, 8-bit PCM*/
|
||||
dev->out_l = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
dev->out_r = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x40: /*Mono, 16-bit PCM*/
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_l = dev->out_r = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0x50: /*Stereo, 16-bit PCM*/
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_l = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_r = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
break;
|
||||
} else switch (dev->regs[8] & 0xf0) {
|
||||
case 0x00: /*Mono, 8-bit PCM*/
|
||||
dev->out_l = dev->out_r = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x10: /*Stereo, 8-bit PCM*/
|
||||
dev->out_l = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
dev->out_r = (dma_channel_read(dev->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x40: /*Mono, 16-bit PCM*/
|
||||
case 0xc0: /*Mono, 16-bit PCM Big-Endian should not happen on x86*/
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_l = dev->out_r = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0x50: /*Stereo, 16-bit PCM*/
|
||||
case 0xd0: /*Stereo, 16-bit PCM Big-Endian. Should not happen on x86*/
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_l = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
temp = dma_channel_read(dev->dma);
|
||||
dev->out_r = (dma_channel_read(dev->dma) << 8) | temp;
|
||||
break;
|
||||
|
||||
case 0xa0: /*TODO Mono, ADPCM, 4-bit*/
|
||||
case 0xb0: /*TODO Stereo, ADPCM, 4-bit*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->regs[6] & 0x80) // Mute Left-Channel
|
||||
dev->out_l = 0;
|
||||
else
|
||||
dev->out_l = (dev->out_l * cs423x_vols[dev->regs[6] & 0x3f]) >> 16;
|
||||
|
||||
if (dev->regs[7] & 0x80) // Mute Right-Channel
|
||||
dev->out_r = 0;
|
||||
else
|
||||
dev->out_r = (dev->out_r * cs423x_vols[dev->regs[7] & 0x3f]) >> 16;
|
||||
|
||||
if (dev->regs[26] & 0x40) // Mono Output Mute
|
||||
dev->out_l = dev->out_r = 0;
|
||||
|
||||
if (dev->count < 0) {
|
||||
dev->count = dev->regs[15] | (dev->regs[14] << 8);
|
||||
if (! (dev->status & 0x01)) {
|
||||
dev->status |= 0x01;
|
||||
if (dev->regs[10] & 2)
|
||||
picint(1 << dev->irq);
|
||||
}
|
||||
}
|
||||
|
||||
dev->count--;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cs423x_init(cs423x_t *dev)
|
||||
{
|
||||
double attenuation;
|
||||
int c;
|
||||
|
||||
dev->enable = 0;
|
||||
|
||||
dev->status = 0xcc;
|
||||
dev->indx = dev->trd = 0;
|
||||
dev->mce = 0x40;
|
||||
dev->initb = 0;
|
||||
dev->mode2 = 0;
|
||||
|
||||
dev->regs[0] = dev->regs[1] = 0;
|
||||
dev->regs[2] = dev->regs[3] = 0x88;
|
||||
dev->regs[4] = dev->regs[5] = 0x88;
|
||||
dev->regs[6] = dev->regs[7] = 0x80;
|
||||
dev->regs[8] = 0;
|
||||
dev->regs[9] = 0x08;
|
||||
dev->regs[10] = dev->regs[11] = 0;
|
||||
dev->regs[12] = 0x8a;
|
||||
dev->regs[13] = 0;
|
||||
dev->regs[14] = dev->regs[15] = 0;
|
||||
dev->regs[16] = dev->regs[17] = 0;
|
||||
dev->regs[18] = dev->regs[19] = 0x88;
|
||||
dev->regs[22] = 0x80;
|
||||
dev->regs[24] = 0;
|
||||
dev->regs[25] = CS4231; //CS4231 for GUS MAX
|
||||
dev->regs[26] = 0x80;
|
||||
dev->regs[29] = 0x80;
|
||||
|
||||
dev->out_l = 0;
|
||||
dev->out_r = 0;
|
||||
|
||||
for (c = 0; c < 64; c++) { // DAC and Loopback attenuation
|
||||
attenuation = 0.0;
|
||||
if (c & 0x01) attenuation -= 1.5;
|
||||
if (c & 0x02) attenuation -= 3.0;
|
||||
if (c & 0x04) attenuation -= 6.0;
|
||||
if (c & 0x08) attenuation -= 12.0;
|
||||
if (c & 0x10) attenuation -= 24.0;
|
||||
if (c & 0x20) attenuation -= 48.0;
|
||||
|
||||
attenuation = pow(10, attenuation / 10);
|
||||
cs423x_vols[c] = (int)(attenuation * 65536);
|
||||
}
|
||||
|
||||
timer_add(cs423x_poll, &dev->timer_count, &dev->enable, dev);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cs423x_speed_changed(cs423x_t *dev)
|
||||
{
|
||||
dev->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)dev->freq));
|
||||
}
|
||||
|
||||
@@ -1,73 +1,94 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the Crystal CS423x driver.
|
||||
*
|
||||
* Version: @(#)snd_cs423x.h 1.0.0 2018/11/27
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct cs423x_t
|
||||
{
|
||||
int index;
|
||||
uint8_t regs[32];
|
||||
uint8_t status;
|
||||
|
||||
int trd;
|
||||
int mce;
|
||||
int ia4;
|
||||
int mode2;
|
||||
int initb;
|
||||
|
||||
int count;
|
||||
|
||||
int16_t out_l, out_r;
|
||||
|
||||
int64_t enable;
|
||||
|
||||
int irq, dma;
|
||||
|
||||
int64_t freq;
|
||||
|
||||
int64_t timer_count, timer_latch;
|
||||
|
||||
int16_t buffer[SOUNDBUFLEN * 2];
|
||||
int pos;
|
||||
} cs423x_t;
|
||||
|
||||
void cs423x_setirq(cs423x_t *cs423x, int irq);
|
||||
void cs423x_setdma(cs423x_t *cs423x, int dma);
|
||||
|
||||
uint8_t cs423x_read(uint16_t addr, void *p);
|
||||
void cs423x_write(uint16_t addr, uint8_t val, void *p);
|
||||
|
||||
void cs423x_update(cs423x_t *cs423x);
|
||||
void cs423x_speed_changed(cs423x_t *cs423x);
|
||||
|
||||
void cs423x_init(cs423x_t *cs423x);
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the Crystal CS423x driver.
|
||||
*
|
||||
* Version: @(#)snd_cs423x.h 1.0.1 2019/01/13
|
||||
*
|
||||
* Authors: Altheos, <altheos@varcem.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018,2019 Altheos.
|
||||
* Copyright 2018,2019 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SND_CS423X_H
|
||||
# define SND_CS423X_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
int indx;
|
||||
uint8_t regs[32];
|
||||
uint8_t status;
|
||||
|
||||
int trd;
|
||||
int mce;
|
||||
int ia4;
|
||||
int mode2;
|
||||
int initb;
|
||||
|
||||
int count;
|
||||
|
||||
int16_t out_l, out_r;
|
||||
|
||||
int64_t enable;
|
||||
|
||||
int irq, dma;
|
||||
|
||||
int64_t freq;
|
||||
|
||||
int64_t timer_count,
|
||||
timer_latch;
|
||||
|
||||
int16_t buffer[SOUNDBUFLEN * 2];
|
||||
int pos;
|
||||
} cs423x_t;
|
||||
|
||||
|
||||
extern void cs423x_setirq(cs423x_t *, int irq);
|
||||
extern void cs423x_setdma(cs423x_t *, int dma);
|
||||
|
||||
extern uint8_t cs423x_read(uint16_t addr, void *priv);
|
||||
extern void cs423x_write(uint16_t addr, uint8_t val, void *priv);
|
||||
|
||||
extern void cs423x_update(cs423x_t *);
|
||||
extern void cs423x_speed_changed(cs423x_t *);
|
||||
|
||||
extern void cs423x_init(cs423x_t *);
|
||||
|
||||
|
||||
#endif /*SND_CS423X_H*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,13 +8,13 @@
|
||||
*
|
||||
* Sound devices support module.
|
||||
*
|
||||
* Version: @(#)sound_dev.c 1.0.11 2018/11/27
|
||||
* Version: @(#)sound_dev.c 1.0.12 2019/01/13
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
*
|
||||
* Implement a generic NVRAM/CMOS/RTC device.
|
||||
*
|
||||
* Version: @(#)nvr.c 1.0.13 2018/11/01
|
||||
* Version: @(#)nvr.c 1.0.14 2019/01/03
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
@@ -60,7 +60,9 @@
|
||||
int nvr_dosave; /* NVR is dirty, needs saved */
|
||||
|
||||
|
||||
static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
static const int8_t days_in_month[12] = {
|
||||
31,28,31,30,31,30,31,31,30,31,30,31
|
||||
};
|
||||
static struct tm intclk;
|
||||
static nvr_t *saved_nvr = NULL;
|
||||
|
||||
|
||||
5
src/pc.c
5
src/pc.c
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Main emulator module where most things are controlled.
|
||||
*
|
||||
* Version: @(#)pc.c 1.0.61 2018/11/13
|
||||
* Version: @(#)pc.c 1.0.62 2018/11/22
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -873,9 +873,6 @@ pc_init(void)
|
||||
codegen_init();
|
||||
#endif
|
||||
|
||||
#ifdef WALTJE_SERIAL
|
||||
serial_init();
|
||||
#endif
|
||||
keyboard_init();
|
||||
joystick_init();
|
||||
video_init();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Define the various platform support functions.
|
||||
*
|
||||
* Version: @(#)plat.h 1.0.21 2018/11/20
|
||||
* Version: @(#)plat.h 1.0.22 2018/11/24
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
@@ -191,7 +191,6 @@ extern int plat_midi_write(uint8_t val);
|
||||
extern int plat_midi_get_num_devs();
|
||||
extern void plat_midi_get_dev_name(int num, char *s);
|
||||
|
||||
|
||||
/* Thread support. */
|
||||
typedef void thread_t;
|
||||
typedef void event_t;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Supported Languages database.
|
||||
#
|
||||
# Version: @(#)VARCem.lang 1.0.5 2018/10/27
|
||||
# Version: @(#)VARCem.lang 1.0.6 2018/12/08
|
||||
#
|
||||
# Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
#
|
||||
@@ -51,6 +51,7 @@ DU,0413,LANG_DUTCH,SUBLANG_DUTCH,Dutch
|
||||
ES,040a,LANG_SPANISH,SUBLANG_SPANISH,Spanish
|
||||
FI,040b,LANG_FINNISH,SUBLANG_FINNISH_FINLAND,Finnish
|
||||
FR,040c,LANG_FRENCH,SUBLANG_FRENCH,French
|
||||
HE,040d,LANG_HEBREW,SUBLANG_HEBREW,Hebrew
|
||||
IT,0410,LANG_ITALIAN,SUBLANG_ITALIAN,Italian
|
||||
JP,0411,LANG_JAPANESE,SUBLANG_JAPANESE_JAPAN,Japanese
|
||||
KR,0412,LANG_KOREAN,SUBLANG_KOREAN,Korean
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
*
|
||||
* Application resource script for Windows.
|
||||
*
|
||||
* Version: @(#)VARCem.rc 1.0.35 2018/11/05
|
||||
* Version: @(#)VARCem.rc 1.0.36 2019/01/13
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
@@ -226,7 +226,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||
VALUE "FileDescription", "Virtual ARchaeological Computer EMulator"
|
||||
VALUE "FileVersion", EMU_VERSION
|
||||
VALUE "InternalName", EMU_NAME
|
||||
VALUE "LegalCopyright", "Copyright Fred N. van Kempen and others, 2007-2018, Released under a mixed BSD 3-Clause and GPL License"
|
||||
VALUE "LegalCopyright", "Copyright Fred N. van Kempen and others, 2007-2019, Released under a mixed BSD 3-Clause and GPL License"
|
||||
VALUE "OriginalFilename", "VARCem.exe"
|
||||
VALUE "ProductName", "VARCem Emulator"
|
||||
VALUE "ProductVersion", EMU_VERSION
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
* which require some weird processing. This file allows us
|
||||
* to use a single master for all those languages.
|
||||
*
|
||||
* Version: @(#)VARCem.rpp 1.0.3 2018/11/05
|
||||
* Version: @(#)VARCem.rpp 1.0.4 2019/01/13
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
* Copyright 2018,2019 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
@@ -98,7 +98,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||
VALUE "FileDescription", "VARCem Language Module"
|
||||
VALUE "FileVersion", STR(STR_VERSION)
|
||||
VALUE "InternalName", EMU_NAME
|
||||
VALUE "LegalCopyright", "Copyright 2018 The VARCem Team"
|
||||
VALUE "LegalCopyright", "Copyright 2018,2019 The VARCem Team"
|
||||
VALUE "OriginalFilename", DLLNAME(LANG)
|
||||
VALUE "ProductName", "VARCem Emulator"
|
||||
VALUE "ProductVersion", EMU_VERSION
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#
|
||||
# Makefile for Windows systems using the MinGW32 environment.
|
||||
#
|
||||
# Version: @(#)Makefile.mingw 1.0.70 2018/11/30
|
||||
# Version: @(#)Makefile.mingw 1.0.71 2019/01/13
|
||||
#
|
||||
# Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
#
|
||||
# Copyright 2017,2018 Fred N. van Kempen.
|
||||
# Copyright 2017-2018 Fred N. van Kempen.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with
|
||||
# or without modification, are permitted provided that the
|
||||
@@ -140,6 +140,9 @@ endif
|
||||
ifndef PAS16
|
||||
PAS16 := n
|
||||
endif
|
||||
ifndef GUSMAX
|
||||
GUSMAX := n
|
||||
endif
|
||||
ifndef XL24
|
||||
XL24 := n
|
||||
endif
|
||||
@@ -152,9 +155,6 @@ endif
|
||||
ifndef HOSTCD
|
||||
HOSTCD := n
|
||||
endif
|
||||
ifndef GUSMAX
|
||||
GUSMAX := n
|
||||
endif
|
||||
|
||||
|
||||
# Name of the executable.
|
||||
@@ -186,10 +186,10 @@ ifeq ($(DEV_BUILD), y)
|
||||
PORTABLE3 := y
|
||||
I686 := y
|
||||
PAS16 := y
|
||||
GUSMAX := y
|
||||
XL24 := y
|
||||
WONDER := y
|
||||
HOSTCD := y
|
||||
GUSMAX := y
|
||||
endif
|
||||
|
||||
|
||||
@@ -558,6 +558,11 @@ ifeq ($(DEV_BRANCH), y)
|
||||
DEVBROBJ += snd_pas16.o
|
||||
endif
|
||||
|
||||
ifeq ($(GUSMAX), y)
|
||||
OPTS += -DUSE_GUSMAX
|
||||
DEVBROBJ += snd_cs423x.o
|
||||
endif
|
||||
|
||||
ifeq ($(WONDER), y)
|
||||
OPTS += -DUSE_WONDER
|
||||
endif
|
||||
@@ -575,10 +580,6 @@ ifeq ($(DEV_BRANCH), y)
|
||||
OPTS += -DUSE_HOST_CDROM
|
||||
endif
|
||||
|
||||
ifeq ($(GUSMAX), y)
|
||||
OPTS += -DUSE_GUSMAX
|
||||
DEVBROBJ += snd_cs423x.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
@@ -740,7 +741,7 @@ VIDOBJ := video.o \
|
||||
PLATOBJ := win.o \
|
||||
win_lang.o win_dynld.o win_opendir.o win_thread.o \
|
||||
win_cdrom.o win_keyboard.o win_mouse.o win_joystick.o \
|
||||
win_midi.o
|
||||
win_serial.o win_midi.o
|
||||
ifeq ($(CRASHDUMP), y)
|
||||
PLATOBJ += win_crashdump.o
|
||||
endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
* Windows and UNIX systems, with support for FTDI and Prolific
|
||||
* USB ports. Support for these has been removed.
|
||||
*
|
||||
* Version: @(#)win_serial.c 1.0.4 2018/10/07
|
||||
* Version: @(#)win_serial.c 1.0.5 2018/11/22
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
@@ -53,79 +53,88 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define PLAT_SERIAL_C
|
||||
#include "../emu.h"
|
||||
#include "../plat.h"
|
||||
#include "../devices/ports/serial.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
char name[80]; /* name of open port */
|
||||
void (*rd_done)(void *, int);
|
||||
void *rd_arg;
|
||||
HANDLE handle;
|
||||
OVERLAPPED rov, /* READ and WRITE events */
|
||||
wov;
|
||||
int tmo; /* current timeout value */
|
||||
DCB dcb, /* terminal settings */
|
||||
odcb;
|
||||
thread_t *tid; /* pointer to receiver thread */
|
||||
char buff[1024];
|
||||
int icnt, ihead, itail;
|
||||
} serial_t;
|
||||
|
||||
|
||||
/* Handle the receiving of data from the host port. */
|
||||
static void
|
||||
bhtty_reader(void *arg)
|
||||
reader_thread(void *arg)
|
||||
{
|
||||
BHTTY *pp = (BHTTY *)arg;
|
||||
unsigned char b;
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
uint8_t b;
|
||||
DWORD n;
|
||||
|
||||
pclog("%s: thread started\n", pp->name);
|
||||
INFO("%s: thread started\n", dev->name);
|
||||
|
||||
/* As long as the channel is open.. */
|
||||
while (pp->tid != NULL) {
|
||||
while (dev->tid != NULL) {
|
||||
/* Post a READ on the device. */
|
||||
n = 0;
|
||||
if (ReadFile(pp->handle, &b, (DWORD)1, &n, &pp->rov) == FALSE) {
|
||||
if (ReadFile(dev->handle, &b, (DWORD)1, &n, &dev->rov) == FALSE) {
|
||||
n = GetLastError();
|
||||
if (n != ERROR_IO_PENDING) {
|
||||
/* Not good, we got an error. */
|
||||
pclog("%s: I/O error %d in read!\n", pp->name, n);
|
||||
ERRLOG("%s: I/O error %i in read!\n", dev->name, n);
|
||||
break;
|
||||
}
|
||||
|
||||
/* The read is pending, wait for it.. */
|
||||
if (GetOverlappedResult(pp->handle, &pp->rov, &n, TRUE) == FALSE) {
|
||||
if (GetOverlappedResult(dev->handle, &dev->rov, &n, TRUE) == FALSE) {
|
||||
n = GetLastError();
|
||||
pclog("%s: I/O error %d in read!\n", pp->name, n);
|
||||
ERRLOG("%s: I/O error %i in read!\n", dev->name, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pclog("%s: got %d bytes of data\n", pp->name, n);
|
||||
pclog(0,"%s: got %i bytes of data\n", dev->name, n);
|
||||
if (n == 1) {
|
||||
/* We got data, update stuff. */
|
||||
if (pp->icnt < sizeof(pp->buff)) {
|
||||
pclog("%s: queued byte %02x (%d)\n", pp->name, b, pp->icnt+1);
|
||||
pp->buff[pp->ihead++] = b;
|
||||
pp->ihead &= (sizeof(pp->buff)-1);
|
||||
pp->icnt++;
|
||||
if (dev->icnt < sizeof(dev->buff)) {
|
||||
pclog(0,"%s: queued byte %02x (%i)\n", dev->name, b, dev->icnt+1);
|
||||
dev->buff[dev->ihead++] = b;
|
||||
dev->ihead &= (sizeof(dev->buff)-1);
|
||||
dev->icnt++;
|
||||
|
||||
/* Do a callback to let them know. */
|
||||
if (pp->rd_done != NULL)
|
||||
pp->rd_done(pp->rd_arg, n);
|
||||
if (dev->rd_done != NULL)
|
||||
dev->rd_done(dev->rd_arg, n);
|
||||
} else {
|
||||
pclog("%s: RX buffer overrun!\n", pp->name);
|
||||
ERRLOG("%s: RX buffer overrun!\n", dev->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Error or done, clean up. */
|
||||
pp->tid = NULL;
|
||||
pclog("%s: thread stopped.\n", pp->name);
|
||||
dev->tid = NULL;
|
||||
INFO("%s: thread stopped.\n", dev->name);
|
||||
}
|
||||
|
||||
|
||||
/* Set the state of a port. */
|
||||
int
|
||||
bhtty_sstate(BHTTY *pp, void *arg)
|
||||
static int
|
||||
set_state(serial_t *dev, void *arg)
|
||||
{
|
||||
/* Make sure we can do this. */
|
||||
if (arg == NULL) {
|
||||
pclog("%s: invalid argument\n", pp->name);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (SetCommState(pp->handle, (DCB *)arg) == FALSE) {
|
||||
/* Mark an error. */
|
||||
pclog("%s: set state: %d\n", pp->name, GetLastError());
|
||||
if (SetCommState(dev->handle, (DCB *)arg) == FALSE) {
|
||||
/* Mark as error. */
|
||||
ERRLOG("%s: set state: %i\n", dev->name, GetLastError());
|
||||
return(-1);
|
||||
}
|
||||
|
||||
@@ -134,18 +143,12 @@ bhtty_sstate(BHTTY *pp, void *arg)
|
||||
|
||||
|
||||
/* Fetch the state of a port. */
|
||||
int
|
||||
bhtty_gstate(BHTTY *pp, void *arg)
|
||||
static int
|
||||
get_state(serial_t *dev, void *arg)
|
||||
{
|
||||
/* Make sure we can do this. */
|
||||
if (arg == NULL) {
|
||||
pclog("%s: invalid argument\n", pp->name);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (GetCommState(pp->handle, (DCB *)arg) == FALSE) {
|
||||
/* Mark an error. */
|
||||
pclog("%s: get state: %d\n", pp->name, GetLastError());
|
||||
if (GetCommState(dev->handle, (DCB *)arg) == FALSE) {
|
||||
/* Mark as error. */
|
||||
ERRLOG("%s: get state: %i\n", dev->name, GetLastError());
|
||||
return(-1);
|
||||
}
|
||||
|
||||
@@ -154,42 +157,42 @@ bhtty_gstate(BHTTY *pp, void *arg)
|
||||
|
||||
|
||||
/* Enable or disable RTS/CTS mode (hardware handshaking.) */
|
||||
int
|
||||
bhtty_crtscts(BHTTY *pp, char yesno)
|
||||
static int
|
||||
set_crtscts(serial_t *dev, int8_t yes)
|
||||
{
|
||||
/* Get the current mode. */
|
||||
if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (get_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
switch(yesno) {
|
||||
switch (yes) {
|
||||
case 0: /* disable CRTSCTS */
|
||||
pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */
|
||||
pp->dcb.fDsrSensitivity = 0;
|
||||
dev->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */
|
||||
dev->dcb.fDsrSensitivity = 0;
|
||||
|
||||
pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */
|
||||
dev->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */
|
||||
|
||||
pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */
|
||||
pp->dcb.fOutX = 0;
|
||||
pp->dcb.fInX = 0;
|
||||
dev->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */
|
||||
dev->dcb.fOutX = 0;
|
||||
dev->dcb.fInX = 0;
|
||||
break;
|
||||
|
||||
case 1: /* enable CRTSCTS */
|
||||
pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */
|
||||
pp->dcb.fDsrSensitivity = 0;
|
||||
dev->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */
|
||||
dev->dcb.fDsrSensitivity = 0;
|
||||
|
||||
pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */
|
||||
dev->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */
|
||||
|
||||
pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */
|
||||
pp->dcb.fOutX = 0;
|
||||
pp->dcb.fInX = 0;
|
||||
dev->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */
|
||||
dev->dcb.fOutX = 0;
|
||||
dev->dcb.fInX = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("%s: invalid parameter '%d'!\n", pp->name, yesno);
|
||||
ERRLOG("%s: invalid parameter '%i'!\n", dev->name, yes);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Set new mode. */
|
||||
if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (set_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -197,13 +200,15 @@ bhtty_crtscts(BHTTY *pp, char yesno)
|
||||
|
||||
/* Set the port parameters. */
|
||||
int
|
||||
bhtty_params(BHTTY *pp, char dbit, char par, char sbit)
|
||||
plat_serial_params(void *arg, char dbit, char par, char sbit)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
|
||||
/* Get the current mode. */
|
||||
if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (get_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
/* Set the desired word length. */
|
||||
switch((int)dbit) {
|
||||
switch ((int)dbit) {
|
||||
case -1: /* no change */
|
||||
break;
|
||||
|
||||
@@ -214,36 +219,36 @@ bhtty_params(BHTTY *pp, char dbit, char par, char sbit)
|
||||
|
||||
case 7:
|
||||
case 8:
|
||||
pp->dcb.ByteSize = dbit;
|
||||
dev->dcb.ByteSize = dbit;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("%s: invalid parameter '%d'!\n", pp->name, dbit);
|
||||
ERRLOG("%s: invalid parameter '%i'!\n", dev->name, dbit);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Set the type of parity encoding. */
|
||||
switch((int)par) {
|
||||
switch ((int)par) {
|
||||
case -1: /* no change */
|
||||
case ' ':
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 'N':
|
||||
pp->dcb.fParity = FALSE;
|
||||
pp->dcb.Parity = NOPARITY;
|
||||
dev->dcb.fParity = FALSE;
|
||||
dev->dcb.Parity = NOPARITY;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 'O':
|
||||
pp->dcb.fParity = TRUE;
|
||||
pp->dcb.Parity = ODDPARITY;
|
||||
dev->dcb.fParity = TRUE;
|
||||
dev->dcb.Parity = ODDPARITY;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 'E':
|
||||
pp->dcb.fParity = TRUE;
|
||||
pp->dcb.Parity = EVENPARITY;
|
||||
dev->dcb.fParity = TRUE;
|
||||
dev->dcb.Parity = EVENPARITY;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
@@ -253,30 +258,30 @@ bhtty_params(BHTTY *pp, char dbit, char par, char sbit)
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("%s: invalid parameter '%c'!\n", pp->name, par);
|
||||
ERRLOG("%s: invalid parameter '%c'!\n", dev->name, par);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Set the number of stop bits. */
|
||||
switch((int)sbit) {
|
||||
switch ((int)sbit) {
|
||||
case -1: /* no change */
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pp->dcb.StopBits = ONESTOPBIT;
|
||||
dev->dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pp->dcb.StopBits = TWOSTOPBITS;
|
||||
dev->dcb.StopBits = TWOSTOPBITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("%s: invalid parameter '%d'!\n", pp->name, sbit);
|
||||
ERRLOG("%s: invalid parameter '%i'!\n", dev->name, sbit);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Set new mode. */
|
||||
if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (set_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -284,13 +289,14 @@ bhtty_params(BHTTY *pp, char dbit, char par, char sbit)
|
||||
|
||||
/* Put a port in transparent ("raw") state. */
|
||||
void
|
||||
bhtty_raw(BHTTY *pp, void *arg)
|
||||
plat_serial_raw(void *arg, void *data)
|
||||
{
|
||||
DCB *dcb = (DCB *)arg;
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
DCB *dcb = (DCB *)data;
|
||||
|
||||
/* Make sure we can do this. */
|
||||
if (arg == NULL) {
|
||||
pclog("%s: invalid parameter\n", pp->name);
|
||||
if (dcb == NULL) {
|
||||
ERRLOG("%s: invalid parameter\n", dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -328,10 +334,12 @@ bhtty_raw(BHTTY *pp, void *arg)
|
||||
|
||||
/* Set the port speed. */
|
||||
int
|
||||
bhtty_speed(BHTTY *pp, long speed)
|
||||
plat_serial_speed(void *arg, long speed)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
|
||||
/* Get the current mode and speed. */
|
||||
if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (get_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
/*
|
||||
* Set speed.
|
||||
@@ -340,10 +348,10 @@ bhtty_speed(BHTTY *pp, long speed)
|
||||
* with DCB_xxx speed values here, but we removed that
|
||||
* and just hardcode the speed value into DCB. --FvK
|
||||
*/
|
||||
pp->dcb.BaudRate = speed;
|
||||
dev->dcb.BaudRate = speed;
|
||||
|
||||
/* Set new speed. */
|
||||
if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1);
|
||||
if (set_state(dev, &dev->dcb) < 0) return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -351,25 +359,26 @@ bhtty_speed(BHTTY *pp, long speed)
|
||||
|
||||
/* Clean up and flush. */
|
||||
int
|
||||
bhtty_flush(BHTTY *pp)
|
||||
plat_serial_flush(void *arg)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
DWORD dwErrs;
|
||||
COMSTAT cst;
|
||||
|
||||
/* First, clear any errors. */
|
||||
(void)ClearCommError(pp->handle, &dwErrs, &cst);
|
||||
(void)ClearCommError(dev->handle, &dwErrs, &cst);
|
||||
|
||||
/* Now flush all buffers. */
|
||||
if (PurgeComm(pp->handle,
|
||||
if (PurgeComm(dev->handle,
|
||||
(PURGE_RXABORT | PURGE_TXABORT | \
|
||||
PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) {
|
||||
pclog("%s: flush: %d\n", pp->name, GetLastError());
|
||||
ERRLOG("%s: flush: %i\n", dev->name, GetLastError());
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Re-clear any errors. */
|
||||
if (ClearCommError(pp->handle, &dwErrs, &cst) == FALSE) {
|
||||
pclog("%s: clear errors: %d\n", pp->name, GetLastError());
|
||||
if (ClearCommError(dev->handle, &dwErrs, &cst) == FALSE) {
|
||||
ERRLOG("%s: clear errors: %i\n", dev->name, GetLastError());
|
||||
return(-1);
|
||||
}
|
||||
|
||||
@@ -377,80 +386,76 @@ bhtty_flush(BHTTY *pp)
|
||||
}
|
||||
|
||||
|
||||
/* Close an open serial port. */
|
||||
/* API: close an open serial port. */
|
||||
void
|
||||
bhtty_close(BHTTY *pp)
|
||||
plat_serial_close(void *arg)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
|
||||
/* If the polling thread is running, stop it. */
|
||||
(void)bhtty_active(pp, 0);
|
||||
plat_serial_active(arg, 0);
|
||||
|
||||
/* Close the event handles. */
|
||||
if (pp->rov.hEvent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pp->rov.hEvent);
|
||||
if (pp->wov.hEvent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pp->wov.hEvent);
|
||||
if (dev->rov.hEvent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(dev->rov.hEvent);
|
||||
if (dev->wov.hEvent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(dev->wov.hEvent);
|
||||
|
||||
if (pp->handle != INVALID_HANDLE_VALUE) {
|
||||
pclog("%s: closing host port\n", pp->name);
|
||||
if (dev->handle != INVALID_HANDLE_VALUE) {
|
||||
INFO("%s: closing host port\n", dev->name);
|
||||
|
||||
/* Restore the previous port state, if any. */
|
||||
(void)bhtty_sstate(pp, &pp->odcb);
|
||||
set_state(dev, &dev->odcb);
|
||||
|
||||
/* Close the port. */
|
||||
CloseHandle(pp->handle);
|
||||
pp->handle = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(dev->handle);
|
||||
}
|
||||
|
||||
/* Release the control block. */
|
||||
free(pp);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
/* Open a host serial port for I/O. */
|
||||
BHTTY *
|
||||
bhtty_open(char *port, int tmo)
|
||||
/* API: open a host serial port for I/O. */
|
||||
void *
|
||||
plat_serial_open(const char *port, int tmo)
|
||||
{
|
||||
char temp[84];
|
||||
COMMTIMEOUTS to;
|
||||
COMMCONFIG conf;
|
||||
BHTTY *pp;
|
||||
serial_t *dev;
|
||||
DWORD d;
|
||||
|
||||
/* First things first... create a control block. */
|
||||
if ((pp = (BHTTY *)mem_alloc(sizeof(BHTTY))) == NULL) {
|
||||
pclog("%s: out of memory!\n", port);
|
||||
if ((dev = (serial_t *)mem_alloc(sizeof(serial_t))) == NULL) {
|
||||
ERRLOG("%s: out of memory!\n", port);
|
||||
return(NULL);
|
||||
}
|
||||
memset(pp, 0x00, sizeof(BHTTY));
|
||||
strncpy(pp->name, port, sizeof(pp->name)-1);
|
||||
memset(dev, 0x00, sizeof(serial_t));
|
||||
strncpy(dev->name, port, sizeof(dev->name)-1);
|
||||
|
||||
/* Try a regular Win32 serial port. */
|
||||
sprintf(temp, "\\\\.\\%s", pp->name);
|
||||
if ((pp->handle = CreateFile(temp,
|
||||
(GENERIC_READ|GENERIC_WRITE),
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
0)) == INVALID_HANDLE_VALUE) {
|
||||
pclog("%s: open port: %d\n", pp->name, GetLastError());
|
||||
free(pp);
|
||||
sprintf(temp, "\\\\.\\%s", dev->name);
|
||||
if ((dev->handle = CreateFile(temp,
|
||||
(GENERIC_READ|GENERIC_WRITE),
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
0)) == INVALID_HANDLE_VALUE) {
|
||||
ERRLOG("%s: open port: %i\n", dev->name, GetLastError());
|
||||
free(dev);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Create event handles. */
|
||||
pp->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
pp->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
dev->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
dev->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
/* Set up buffer size of the port. */
|
||||
if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) {
|
||||
/* This fails on FTDI-based devices. */
|
||||
pclog("%s: set buffers: %d\n", pp->name, GetLastError());
|
||||
#if 0
|
||||
CloseHandle(pp->handle);
|
||||
free(pp);
|
||||
return(NULL);
|
||||
#endif
|
||||
if (SetupComm(dev->handle, 32768L, 32768L) == FALSE) {
|
||||
/* This fails on FTDI-based devices, so, not fatal. */
|
||||
ERRLOG("%s: set buffers: %i\n", dev->name, GetLastError());
|
||||
}
|
||||
|
||||
/* Grab default config for the driver and set it. */
|
||||
@@ -461,48 +466,44 @@ bhtty_open(char *port, int tmo)
|
||||
/* Change config here... */
|
||||
|
||||
/* Set new configuration. */
|
||||
if (SetCommConfig(pp->handle, &conf, d) == FALSE) {
|
||||
/* This fails on FTDI-based devices. */
|
||||
pclog("%s: set configuration: %d\n", pp->name, GetLastError());
|
||||
#if 0
|
||||
CloseHandle(pp->handle);
|
||||
free(pp);
|
||||
return(NULL);
|
||||
#endif
|
||||
if (SetCommConfig(dev->handle, &conf, d) == FALSE) {
|
||||
/* This fails on FTDI-based devices, so, not fatal. */
|
||||
ERRLOG("%s: set config: %i\n", dev->name, GetLastError());
|
||||
}
|
||||
}
|
||||
pclog("%s: host port '%s' open\n", pp->name, temp);
|
||||
ERRLOG("%s: host port '%s' open\n", dev->name, temp);
|
||||
|
||||
/*
|
||||
* We now have an open port. To allow for clean exit
|
||||
* of the application, we first retrieve the port's
|
||||
* current settings, and save these for later.
|
||||
*/
|
||||
if (bhtty_gstate(pp, &pp->odcb) < 0) {
|
||||
(void)bhtty_close(pp);
|
||||
if (get_state(dev, &dev->odcb) < 0) {
|
||||
plat_serial_close(dev);
|
||||
return(NULL);
|
||||
}
|
||||
memcpy(&pp->dcb, &pp->odcb, sizeof(DCB));
|
||||
memcpy(&dev->dcb, &dev->odcb, sizeof(DCB));
|
||||
|
||||
/* Force the port to BINARY mode. */
|
||||
bhtty_raw(pp, &pp->dcb);
|
||||
plat_serial_raw(dev, &dev->dcb);
|
||||
|
||||
/* Set new state of this port. */
|
||||
if (bhtty_sstate(pp, &pp->dcb) < 0) {
|
||||
(void)bhtty_close(pp);
|
||||
if (set_state(dev, &dev->dcb) < 0) {
|
||||
plat_serial_close(dev);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Just to make sure.. disable RTS/CTS mode. */
|
||||
(void)bhtty_crtscts(pp, 0);
|
||||
set_crtscts(dev, 0);
|
||||
|
||||
/* Set new timeout values. */
|
||||
if (GetCommTimeouts(pp->handle, &to) == FALSE) {
|
||||
pclog("%s: error %d while getting current TO\n",
|
||||
pp->name, GetLastError());
|
||||
(void)bhtty_close(pp);
|
||||
if (GetCommTimeouts(dev->handle, &to) == FALSE) {
|
||||
ERRLOG("%s: error %i while getting current TO\n",
|
||||
dev->name, GetLastError());
|
||||
plat_serial_close(dev);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (tmo < 0) {
|
||||
/* No timeout, immediate return. */
|
||||
to.ReadIntervalTimeout = MAXDWORD;
|
||||
@@ -517,34 +518,36 @@ bhtty_open(char *port, int tmo)
|
||||
to.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
to.ReadTotalTimeoutConstant = tmo;
|
||||
}
|
||||
if (SetCommTimeouts(pp->handle, &to) == FALSE) {
|
||||
pclog("%s: error %d while setting TO\n", pp->name, GetLastError());
|
||||
(void)bhtty_close(pp);
|
||||
if (SetCommTimeouts(dev->handle, &to) == FALSE) {
|
||||
ERRLOG("%s: error %i while setting TO\n", dev->name, GetLastError());
|
||||
plat_serial_close(dev);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Clear all errors and flush all buffers. */
|
||||
if (bhtty_flush(pp) < 0) {
|
||||
(void)bhtty_close(pp);
|
||||
if (plat_serial_flush(dev) < 0) {
|
||||
plat_serial_close(dev);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(pp);
|
||||
return(dev);
|
||||
}
|
||||
|
||||
|
||||
/* Activate the I/O for this port. */
|
||||
/* API: activate the I/O for this port. */
|
||||
int
|
||||
bhtty_active(BHTTY *pp, int flg)
|
||||
plat_serial_active(void *arg, int flg)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
|
||||
if (flg) {
|
||||
pclog("%s: starting thread..\n", pp->name);
|
||||
pp->tid = thread_create(bhtty_reader, pp);
|
||||
INFO("%s: starting thread..\n", dev->name);
|
||||
dev->tid = thread_create(reader_thread, dev);
|
||||
} else {
|
||||
if (pp->tid != NULL) {
|
||||
pclog("%s: stopping thread..\n", pp->name);
|
||||
thread_kill(pp->tid);
|
||||
pp->tid = NULL;
|
||||
if (dev->tid != NULL) {
|
||||
INFO("%s: stopping thread..\n", dev->name);
|
||||
thread_kill(dev->tid);
|
||||
dev->tid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,25 +555,26 @@ bhtty_active(BHTTY *pp, int flg)
|
||||
}
|
||||
|
||||
|
||||
/* Try to write data to an open port. */
|
||||
/* API: try to write data to an open port. */
|
||||
int
|
||||
bhtty_write(BHTTY *pp, unsigned char val)
|
||||
plat_serial_write(void *arg, unsigned char val)
|
||||
{
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
DWORD n = 0;
|
||||
|
||||
pclog("%s: writing byte %02x\n", pp->name, val);
|
||||
if (WriteFile(pp->handle, &val, 1, &n, &pp->wov) == FALSE) {
|
||||
pclog(0,"%s: writing byte %02x\n", dev->name, val);
|
||||
if (WriteFile(dev->handle, &val, 1, &n, &dev->wov) == FALSE) {
|
||||
n = GetLastError();
|
||||
if (n != ERROR_IO_PENDING) {
|
||||
/* Not good, we got an error. */
|
||||
pclog("%s: I/O error %d in write!\n", pp->name, n);
|
||||
ERRLOG("%s: I/O error %i in write!\n", dev->name, n);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* The write is pending, wait for it.. */
|
||||
if (GetOverlappedResult(pp->handle, &pp->wov, &n, TRUE) == FALSE) {
|
||||
if (GetOverlappedResult(dev->handle, &dev->wov, &n, TRUE) == FALSE) {
|
||||
n = GetLastError();
|
||||
pclog("%s: I/O error %d in write!\n", pp->name, n);
|
||||
ERRLOG("%s: I/O error %i in write!\n", dev->name, n);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
@@ -580,22 +584,24 @@ pclog("%s: writing byte %02x\n", pp->name, val);
|
||||
|
||||
|
||||
/*
|
||||
* Try to read data from an open port.
|
||||
* API: try to read data from an open port.
|
||||
*
|
||||
* For now, we will use one byte per call. Eventually,
|
||||
* we should go back to loading a buffer full of data,
|
||||
* just to speed things up a bit. --FvK
|
||||
*/
|
||||
int
|
||||
bhtty_read(BHTTY *pp, unsigned char *bufp, int max)
|
||||
plat_serial_read(void *arg, unsigned char *bufp, int max)
|
||||
{
|
||||
if (pp->icnt == 0) return(0);
|
||||
serial_t *dev = (serial_t *)arg;
|
||||
|
||||
if (dev->icnt == 0) return(0);
|
||||
|
||||
while (max-- > 0) {
|
||||
*bufp++ = pp->buff[pp->itail++];
|
||||
pclog("%s: dequeued byte %02x (%d)\n", pp->name, *(bufp-1), pp->icnt);
|
||||
pp->itail &= (sizeof(pp->buff)-1);
|
||||
if (--pp->icnt == 0) break;
|
||||
*bufp++ = dev->buff[dev->itail++];
|
||||
pclog(0,"%s: dequeued byte %02x (%i)\n", dev->name, *(bufp-1), dev->icnt);
|
||||
dev->itail &= (sizeof(dev->buff)-1);
|
||||
if (--dev->icnt == 0) break;
|
||||
}
|
||||
|
||||
return(max);
|
||||
|
||||
Reference in New Issue
Block a user