Modem support and pipe out to ppp.

Allow Ooga Booga and NFL 2K2 to connect to network lobbby at https://www.dreamcastlive.net.
Sadly all other tested games still fail the ppp handshake. Work in progress...
This commit is contained in:
Flyinghead 2018-09-12 13:20:20 +02:00
parent 0e939b5f68
commit e3d99541d6
8 changed files with 1671 additions and 23 deletions

View File

@ -6,7 +6,7 @@
RZDCY_SRC_DIR ?= $(call my-dir)
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ hw/modem/ \
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \
hw/extdev/ hw/arm/ hw/naomi/ imgread/ linux/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/

View File

@ -13,6 +13,7 @@
#include "hw/gdrom/gdrom_if.h"
#include "hw/aica/aica_if.h"
#include "hw/naomi/naomi.h"
#include "hw/modem/modem.h"
#include "hw/flashrom/flashrom.h"
#include "reios/reios.h"
@ -150,7 +151,6 @@ T DYNACALL ReadMem_area0(u32 addr)
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
//EMUERROR3("Read from area0_32 not implemented [GD-ROM], addr=%x,size=%d",addr,sz);
#if DC_PLATFORM == DC_PLATFORM_NAOMI
return (T)ReadMem_naomi(addr,sz);
#else
@ -159,12 +159,10 @@ T DYNACALL ReadMem_area0(u32 addr)
}
else if (likely((addr>= 0x005F6800) && (addr<=0x005F7CFF))) // /*:PVR i/f Control Reg.*/ -> ALL SB registers now
{
//EMUERROR2("Read from area0_32 not implemented [PVR i/f Control Reg], addr=%x",addr);
return (T)sb_ReadMem(addr,sz);
}
else if (likely((addr>= 0x005F8000) && (addr<=0x005F9FFF))) // :TA / PVR Core Reg.
{
//EMUERROR2("Read from area0_32 not implemented [TA / PVR Core Reg], addr=%x",addr);
verify(sz==4);
return (T)pvr_ReadReg(addr);
}
@ -172,8 +170,11 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // :MODEM
{
return (T)libExtDevice_ReadMem_A0_006(addr,sz);
//EMUERROR2("Read from area0_32 not implemented [MODEM], addr=%x",addr);
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
#else
return (T)ModemReadMem_A0_006(addr, sz);
#endif
}
//map 0x0060 to 0x006F
else if ((base >=0x0060) && (base <=0x006F) && (addr>= 0x00600800) && (addr<= 0x006FFFFF)) // :G2 (Reserved)
@ -183,26 +184,21 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0070 to 0x0070
else if ((base ==0x0070) /*&& (addr>= 0x00700000)*/ && (addr<=0x00707FFF)) // :AICA- Sound Cntr. Reg.
{
//EMUERROR2("Read from area0_32 not implemented [AICA- Sound Cntr. Reg], addr=%x",addr);
return (T) ReadMem_aica_reg(addr,sz);//libAICA_ReadReg(addr,sz);
}
//map 0x0071 to 0x0071
else if ((base ==0x0071) /*&& (addr>= 0x00710000)*/ && (addr<= 0x0071000B)) // :AICA- RTC Cntr. Reg.
{
//EMUERROR2("Read from area0_32 not implemented [AICA- RTC Cntr. Reg], addr=%x",addr);
return (T)ReadMem_aica_rtc(addr,sz);
}
//map 0x0080 to 0x00FF
else if ((base >=0x0080) && (base <=0x00FF) /*&& (addr>= 0x00800000) && (addr<=0x00FFFFFF)*/) // :AICA- Wave Memory
{
//EMUERROR2("Read from area0_32 not implemented [AICA- Wave Memory], addr=%x",addr);
//return (T)libAICA_ReadMem_aica_ram(addr,sz);
ReadMemArrRet(aica_ram.data,addr&ARAM_MASK,sz);
}
//map 0x0100 to 0x01FF
else if ((base >=0x0100) && (base <=0x01FF) /*&& (addr>= 0x01000000) && (addr<= 0x01FFFFFF)*/) // :Ext. Device
{
// EMUERROR2("Read from area0_32 not implemented [Ext. Device], addr=%x",addr);
return (T)libExtDevice_ReadMem_A0_010(addr,sz);
}
return 0;
@ -218,13 +214,11 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0000 to 0x001F
if ((base <=0x001F) /*&& (addr<=0x001FFFFF)*/)// :MPX System/Boot ROM
{
//EMUERROR4("Write to [MPX System/Boot ROM] is not possible, addr=%x,data=%x,size=%d",addr,data,sz);
WriteBios(addr,data,sz);
}
//map 0x0020 to 0x0021
else if ((base >=0x0020) && (base <=0x0021) /*&& (addr>= 0x00200000) && (addr<= 0x0021FFFF)*/) // Flash Memory
{
//EMUERROR4("Write to [Flash Memory] , sz?!, addr=%x,data=%x,size=%d",addr,data,sz);
WriteFlash(addr,data,sz);
}
//map 0x0040 to 0x005F -> actually, I'll only map 0x005F to 0x005F, b/c the rest of it is unspammed (left to default handler)
@ -237,7 +231,6 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
//EMUERROR4("Write to area0_32 not implemented [GD-ROM], addr=%x,data=%x,size=%d",addr,data,sz);
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
WriteMem_naomi(addr,data,sz);
#else
@ -246,12 +239,10 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
}
else if ( likely((addr>= 0x005F6800) && (addr<=0x005F7CFF)) ) // /*:PVR i/f Control Reg.*/ -> ALL SB registers
{
//EMUERROR4("Write to area0_32 not implemented [PVR i/f Control Reg], addr=%x,data=%x,size=%d",addr,data,sz);
sb_WriteMem(addr,data,sz);
}
else if ( likely((addr>= 0x005F8000) && (addr<=0x005F9FFF)) ) // TA / PVR Core Reg.
{
//EMUERROR4("Write to area0_32 not implemented [TA / PVR Core Reg], addr=%x,data=%x,size=%d",addr,data,sz);
verify(sz==4);
pvr_WriteReg(addr,data);
}
@ -259,8 +250,11 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // MODEM
{
//EMUERROR4("Write to area0_32 not implemented [MODEM], addr=%x,data=%x,size=%d",addr,data,sz);
libExtDevice_WriteMem_A0_006(addr,data,sz);
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
libExtDevice_WriteMem_A0_006(addr, data, sz);
#else
ModemWriteMem_A0_006(addr, data, sz);
#endif
}
//map 0x0060 to 0x006F
else if ((base >=0x0060) && (base <=0x006F) && (addr>= 0x00600800) && (addr<= 0x006FFFFF)) // G2 (Reserved)
@ -270,29 +264,24 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0070 to 0x0070
else if ((base >=0x0070) && (base <=0x0070) /*&& (addr>= 0x00700000)*/ && (addr<=0x00707FFF)) // AICA- Sound Cntr. Reg.
{
//EMUERROR4("Write to area0_32 not implemented [AICA- Sound Cntr. Reg], addr=%x,data=%x,size=%d",addr,data,sz);
WriteMem_aica_reg(addr,data,sz);
return;
}
//map 0x0071 to 0x0071
else if ((base >=0x0071) && (base <=0x0071) /*&& (addr>= 0x00710000)*/ && (addr<= 0x0071000B)) // AICA- RTC Cntr. Reg.
{
//EMUERROR4("Write to area0_32 not implemented [AICA- RTC Cntr. Reg], addr=%x,data=%x,size=%d",addr,data,sz);
WriteMem_aica_rtc(addr,data,sz);
return;
}
//map 0x0080 to 0x00FF
else if ((base >=0x0080) && (base <=0x00FF) /*&& (addr>= 0x00800000) && (addr<=0x00FFFFFF)*/) // AICA- Wave Memory
{
//EMUERROR4("Write to area0_32 not implemented [AICA- Wave Memory], addr=%x,data=%x,size=%d",addr,data,sz);
//aica_writeram(addr,data,sz);
WriteMemArrRet(aica_ram.data,addr&ARAM_MASK,data,sz);
return;
}
//map 0x0100 to 0x01FF
else if ((base >=0x0100) && (base <=0x01FF) /*&& (addr>= 0x01000000) && (addr<= 0x01FFFFFF)*/) // Ext. Device
{
//EMUERROR4("Write to area0_32 not implemented [Ext. Device], addr=%x,data=%x,size=%d",addr,data,sz);
libExtDevice_WriteMem_A0_010(addr,data,sz);
}
return;

737
core/hw/modem/modem.cpp Normal file
View File

@ -0,0 +1,737 @@
/*
Originally based on nullDC: nullExtDev/modem.cpp
Created on: Sep 9, 2018
Copyright 2018 skmp, flyinghead
This file is part of reicast.
reicast 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.
reicast 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 reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "modem.h"
#include "modem_regs.h"
#include "hw/holly/holly_intc.h"
#include "hw/sh4/sh4_sched.h"
#include "oslib/oslib.h"
#include "pppd.h"
#define MODEM_COUNTRY_RES 0
#define MODEM_COUNTRY_JAP 1
#define MODEM_COUNTRY_USA 2
#define MODEM_MAKER_SEGA 0
#define MODEM_MAKER_ROCKWELL 1
#define MODEM_DEVICE_TYPE_336K 0
#ifdef RELEASE
#define LOG(...)
#else
#define LOG(...) do { printf("[%d.%03d] MODEM ", (int)os_GetSeconds(), (int)(os_GetSeconds() * 1000) % 1000); printf(__VA_ARGS__); putchar('\n'); } while (false);
#endif
const static u32 MODEM_ID[2] =
{
MODEM_COUNTRY_RES,
(MODEM_MAKER_ROCKWELL<<4) | (MODEM_DEVICE_TYPE_336K),
};
static modemreg_t modem_regs;
static u8 dspram[0x1000];
static int modem_sched;
enum ModemStates
{
MS_INVALID, //needs reset
MS_RESET, //reset is low
MS_RESETING, //reset is hi
MS_ST_CONTROLER, //Controller self test
MS_ST_DSP, //DSP self test
MS_END_DSP, //DSP self test end
MS_NORMAL, //Normal operation
};
static ModemStates state = MS_INVALID;
enum ConnectState
{
DISCONNECTED,
DIALING,
RINGING,
HANDSHAKING,
CONNECTED,
};
static ConnectState connect_state = DISCONNECTED;
static void schedule_callback(int ms);
static void update_interrupt()
{
modem_regs.reg1e.RDBIA = modem_regs.reg1e.RDBIE && modem_regs.reg1e.RDBF;
modem_regs.reg1e.TDBIA = modem_regs.reg1e.TDBIE && modem_regs.reg1e.TDBE;
if (modem_regs.reg1f.NCIA || modem_regs.reg1f.NSIA || modem_regs.reg1e.RDBIA || modem_regs.reg1e.TDBIA)
asic_RaiseInterrupt(holly_EXP_8BIT);
else
asic_CancelInterrupt(holly_EXP_8BIT);
}
static u32 get_masked_status(u32 reg)
{
u8 int_mask = dspram[regs_int_mask_addr[reg]];
return int_mask & modem_regs.ptr[reg];
}
#define SET_STATUS_BIT(reg, bit, value) do { \
if ((bit) != (value)) \
{ \
if (!modem_regs.reg1f.NSIE) \
{ \
bit = (value); \
} \
else \
{ \
u8 before = get_masked_status(reg); \
bit = (value); \
if (before != get_masked_status(reg)) \
modem_regs.reg1f.NSIA = 1; \
} \
} \
} while (false);
static void ControllerTestEnd();
static void DSPTestStart();
static void DSPTestEnd();
static double last_dial_time;
#ifndef RELEASE
static double last_comm_stats;
static int sent_bytes;
static int recvd_bytes;
static FILE *recv_fp;
static FILE *sent_fp;
#endif
static int modem_sched_func(int tag, int c, int j)
{
#ifndef RELEASE
if (os_GetSeconds() - last_comm_stats >= 2)
{
if (last_comm_stats != 0)
{
printf("Stats sent %d received %d TDBE %d RDBF %d\n", sent_bytes, recvd_bytes, modem_regs.reg1e.TDBE, modem_regs.reg1e.RDBF);
sent_bytes = 0;
recvd_bytes = 0;
}
last_comm_stats = os_GetSeconds();
}
#endif
switch (state)
{
case MS_ST_CONTROLER:
ControllerTestEnd();
break;
case MS_ST_DSP:
DSPTestStart();
break;
case MS_END_DSP:
DSPTestEnd();
break;
case MS_NORMAL:
modem_regs.reg1f.NEWC = 0; // Not needed when state is CONNECTED but who cares
switch (connect_state)
{
case DIALING:
if (last_dial_time != 0 && os_GetSeconds() - last_dial_time > 0.99)
{
LOG("Switching to RINGING state");
connect_state = RINGING;
schedule_callback(100);
}
else
{
last_dial_time = os_GetSeconds();
modem_regs.reg1e.TDBE = 1;
schedule_callback(1000); // To switch to Ringing state
}
break;
case RINGING:
last_dial_time = 0;
LOG("\t\t *** RINGING STATE ***");
modem_regs.reg1f.NEWS = 1;
if (!modem_regs.reg09.DATA)
{
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RI, 1);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATV25, 1);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATBEL, 1);
}
if (modem_regs.reg12 == 0xAA)
{
// V8 AUTO mode
dspram[0x302] |= 1 << 3; // Detect ANSam
}
break;
case HANDSHAKING:
LOG("\t\t *** HANDSHAKING STATE ***");
if (modem_regs.reg03.RLSDE)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RLSD, 1);
if (modem_regs.reg1f.NSIE)
{
// CONF
if (dspram[regs_int_mask_addr[0x12]] & (1 << 7))
modem_regs.reg1f.NSIA = 1;
// SPEED
if (dspram[regs_int_mask_addr[0x0e]] & 0x1f)
modem_regs.reg1f.NSIA = 1;
// ABCODE
if (dspram[regs_int_mask_addr[0x014]])
modem_regs.reg1f.NSIA = 1;
}
if (modem_regs.reg08.ASYN)
{
modem_regs.reg12 = 0xce; // CONF V34 - K56flex
modem_regs.reg0e.SPEED = 0x10; // 33.6k
}
else
{
// Force the driver to ASYN=1 so it sends raw data
modem_regs.reg12 = 0xa4; // CONF V23
modem_regs.reg0e.SPEED = 0x02; // 1.2k
//modem_regs.reg0e.SPEED = 0x10; // 33.6k. Obviously wrong for V23 but may help some games complaining about low quality link
}
modem_regs.reg14 = 0x00; // ABCODE: no error
modem_regs.reg1f.NEWS = 1;
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RI, 0);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATV25, 0);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATBEL, 0);
SET_STATUS_BIT(0x0f, modem_regs.reg0f.DSR, 1);
if (modem_regs.reg02.v0.V54PE)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.V54DT, 1);
if (modem_regs.reg02.v0.RTSDE)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RTSDT, 1);
// What is this? This is required for games to detect the connection
// Can be set now or at connected state
SET_STATUS_BIT(0x0f, modem_regs.reg0f.FED, 1);
start_pppd();
break;
case CONNECTED:
#ifndef RELEASE
static bool mem_dumped;
if (!mem_dumped)
{
mem_dumped = true;
for (int i = 0 ; i < sizeof(modem_regs); i++)
LOG("modem_regs %02x == %02x", i, modem_regs.ptr[i]);
}
#endif
if (!modem_regs.reg1e.RDBF)
{
int c = read_pppd();
if (c >= 0)
{
//LOG("pppd received %02x", c);
#ifndef RELEASE
recvd_bytes++;
#endif
modem_regs.reg00 = c & 0xFF;
modem_regs.reg1e.RDBF = 1;
if (modem_regs.reg04.FIFOEN)
SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 1);
}
}
modem_regs.reg1e.TDBE = 1;
}
break;
}
update_interrupt();
if (connect_state == HANDSHAKING)
{
connect_state = CONNECTED;
return SH4_MAIN_CLOCK / 1000 * 500; // 500 ms
}
return connect_state == CONNECTED ? (SH4_MAIN_CLOCK / 1000000 * 238) : 0; // 238us
}
static void schedule_callback(int ms)
{
if (modem_sched == 0)
modem_sched = sh4_sched_register(0, &modem_sched_func);
sh4_sched_request(modem_sched, SH4_MAIN_CLOCK / 1000 * ms);
}
#define SetReg16(rh,rl,v) {modem_regs.ptr[rh]=(v)>>8;modem_regs.ptr[rl]=(v)&0xFF; }
static void NormalDefaultRegs()
{
verify(state == MS_NORMAL);
verify(sizeof(regs_write_mask) == sizeof(modem_regs));
verify(sizeof(por_dspram) == sizeof(dspram));
// Default values for normal state
memset(&modem_regs, 0, sizeof(modem_regs));
memcpy(dspram, por_dspram, sizeof(dspram));
modem_regs.reg05.CEQ = 1;
modem_regs.reg12 = 0x76; // CONF: V.32 bis TCM 14400
modem_regs.reg09.DATA = 1;
modem_regs.reg09.DTMF = 1;
modem_regs.reg15.HWRWK = 1;
modem_regs.reg07.RDLE = 1;
modem_regs.reg15.RDWK = 1;
modem_regs.reg03.RLSDE = 1;
modem_regs.reg02.TDE = 1;
modem_regs.reg13.TLVL = 0x9;
modem_regs.reg1e.TDBE = 1;
connect_state = DISCONNECTED;
last_dial_time = 0;
}
static void DSPTestEnd()
{
verify(state==MS_END_DSP);
state=MS_NORMAL;
LOG("DSPTestEnd");
NormalDefaultRegs();
}
static void DSPTestStart()
{
verify(state==MS_ST_DSP);
state=MS_END_DSP;
LOG("DSPTestStart");
modem_regs.reg1e.TDBE = 1;
SetReg16(0x1B,0x1A,0xF083); // EC checksum
SetReg16(0x19,0x18,0x46EE); // Multiplier checksum
SetReg16(0x17,0x16,0x00FA); // RAM checksum
SetReg16(0x15,0x14,0x0A09); // ROM checksum
SetReg16(0x13,0x12,0x3730); // Part number
SetReg16(0x11,0x00,0x2041); // Revision level
schedule_callback(50);
}
static void ControllerTestEnd()
{
verify(state==MS_ST_CONTROLER);
state=MS_ST_DSP;
schedule_callback(50);
}
//End the reset and start internal tests
static void ControllerTestStart()
{
verify(state==MS_RESETING);
//Set Self test values :)
state=MS_ST_CONTROLER;
//k, lets set values
//1E:3 -> set
modem_regs.reg1e.TDBE=1;
/*
RAM1 Checksum = 0xEA3C or 0x451
RAM2 Checksum = 0x5536 or 0x49A5
ROM1 Checksum = 0x5F4C
ROM2 Checksum = 0x3835 or 0x3836
Timer/ROM/RAM = 0x801 or 0xDE00
Part Number = 0x3730 or 0x3731
Revision Level = 0x4241
*/
SetReg16(0x1D,0x1C,0xEA3C);
SetReg16(0x1B,0x1A,0x5536);
SetReg16(0x19,0x18,0x5F4C);
SetReg16(0x17,0x16,0x3835);
SetReg16(0x15,0x14,0x801);
SetReg16(0x13,0x12,0x3730);
SetReg16(0x11,0x0,0x4241);
ControllerTestEnd();
}
static void modem_reset(u32 v)
{
if (v==0)
{
memset(&modem_regs,0,sizeof(modem_regs));
state=MS_RESET;
LOG("Modem reset start ...");
}
else
{
stop_pppd();
memset(&modem_regs,0,sizeof(modem_regs));
state=MS_RESETING;
modem_regs.ptr[0x20]=1;
ControllerTestStart();
LOG("Modem reset end ...");
}
}
static void check_start_handshake()
{
if (modem_regs.reg09.DTR
&& (modem_regs.reg09.DATA || modem_regs.reg15.AUTO)
&& connect_state == RINGING)
{
LOG("DTR asserted. starting handshaking");
connect_state = HANDSHAKING;
schedule_callback(1000);
}
}
static bool word_dspram_write;
static bool module_download;
static u32 reg1b_save;
static u8 download_crc;
static void ModemNormalWrite(u32 reg, u32 data)
{
#ifndef RELEASE
if (recv_fp == NULL)
{
recv_fp = fopen("ppp_recv.dump", "w");
sent_fp = fopen("ppp_sent.dump", "w");
}
#endif
//if (!module_download && reg != 0x10)
// LOG("ModemNormalWrite : %03X=%X", reg,data);
u32 old = modem_regs.ptr[reg];
modem_regs.ptr[reg] = (old & ~regs_write_mask[reg]) | (data & regs_write_mask[reg]);
switch(reg)
{
case 0x02:
if (modem_regs.reg02.v0.V54PE)
LOG("V54PE set");
if (modem_regs.reg02.v0.V54AE)
LOG("V54AE set");
if (modem_regs.reg02.v0.V54TE)
LOG("V54TE set");
modem_regs.reg0f.RTSDT = modem_regs.reg02.v0.RTSDE & connect_state == CONNECTED;
break;
case 0x06:
LOG("PEN = %d", modem_regs.reg06.PEN);
if (modem_regs.reg06.PEN)
die("PEN = 1");
if (modem_regs.reg06.HDLC)
die("HDLC = 1");
break;
case 0x08:
LOG("TPDM = %d ASYN = %d", modem_regs.reg08.TPDM, modem_regs.reg08.ASYN);
break;
case 0x09:
check_start_handshake(); // DTR and DATA
break;
case 0x10: // TBUFFER
//LOG("ModemNormalWrite : TBUFFER = %X", data);
if (module_download)
{
download_crc = (download_crc << 1) + ((download_crc & 0x80) >> 7) + (data & 0xFF);
}
else if (connect_state == DISCONNECTED || connect_state == DIALING)
{
if (connect_state == DISCONNECTED)
{
LOG("Switching to DIALING...");
connect_state = DIALING;
}
schedule_callback(100);
}
else if (connect_state == CONNECTED && modem_regs.reg08.RTS)
{
//LOG("pppd write %02x", data);
#ifndef RELEASE
sent_bytes++;
if (sent_fp)
fputc(data, sent_fp);
#endif
write_pppd(data);
if (!modem_regs.reg08.ASYN || modem_regs.reg12 == 0xa4) // CONF = V23
// Wait for the next schedule before setting the TX empty flag?
modem_regs.reg1e.TDBE = 0;
else
modem_regs.reg1e.TDBE = 1;
}
break;
case 0x11:
LOG("PARSL = %d", modem_regs.reg11.PARSL);
die("PARSL");
break;
case 0x14: // ABCODE
if (data == 0x4f || data == 0x5f)
{
reg1b_save = modem_regs.ptr[0x1b];
modem_regs.ptr[0x1b] = data;
//LOG("SPX/CTL download initiated");
module_download = true;
download_crc = 0;
}
else if (data == 0 && module_download)
{
// If module download is in progress, this signals the end of it
modem_regs.reg17 = 0xFF;
modem_regs.reg16 = download_crc;
// Restore reg 1b
modem_regs.ptr[0x1b] = reg1b_save;
module_download = false;
//LOG("SPX/CTL download finished CRC %02x", download_crc);
}
break;
case 0x15:
check_start_handshake(); // AUTO
break;
//Data Write Regs, for transfers to DSP
case 0x18: // MEDAL
break;
case 0x19: // MEDAM
word_dspram_write = true;
break;
case 0x1a:
verify(connect_state != CONNECTED || !modem_regs.reg1a.SCIBE);
break;
//Address low
case 0x1C: // MEADDL
break;
case 0x1D: // MEADDH
if (modem_regs.reg1c_1d.MEMW && !(old & 1 << 13))
{
word_dspram_write = false;
}
if (modem_regs.reg1c_1d.MEACC)
{
modem_regs.reg1c_1d.MEACC=0;
modem_regs.reg1f.NEWS = 1;
u32 dspram_addr = modem_regs.reg1c_1d.MEMADD_l | (modem_regs.reg1c_1d.MEMADD_h << 8);
if (modem_regs.reg1c_1d.MEMW)
{
//LOG("DSP mem Write%s address %08x = %x",
// word_dspram_write ? " (w)" : "",
// dspram_addr,
// modem_regs.reg18_19 );
if (word_dspram_write)
{
if (dspram_addr & 1)
{
dspram[dspram_addr] = modem_regs.reg18_19 & 0xFF;
dspram[dspram_addr + 1] = (modem_regs.reg18_19 >> 8) & 0xFF;
}
else
*(u16*)&dspram[dspram_addr] = modem_regs.reg18_19;
}
else
dspram[dspram_addr] = modem_regs.reg18_19 & 0xFF;
}
else
{
if (dspram_addr & 1)
modem_regs.reg18_19 = dspram[dspram_addr] | (dspram[dspram_addr + 1] << 8);
else
modem_regs.reg18_19 = *(u16*)&dspram[dspram_addr];
//LOG("DSP mem Read address %08x == %x",
// dspram_addr,
// modem_regs.reg18_19 );
}
}
break;
case 0x1F:
if (!modem_regs.reg1f.NCIE)
modem_regs.reg1f.NCIA = 0;
if (modem_regs.reg1f.NEWC)
{
if(modem_regs.reg1a.SFRES)
{
modem_regs.reg1a.SFRES = 0;
LOG("Soft Reset SET && NEWC, executing reset and init");
modem_reset(1);
}
else
{
modem_regs.reg1f.NEWC = 0; // accept the settings
if (modem_regs.reg1f.NCIE)
modem_regs.reg1f.NCIA = 1;
LOG("NEWC CONF=%x", modem_regs.reg12);
}
}
// Don't allow NEWS to be set if 0
if (old & (1 << 3) == 0)
modem_regs.reg1f.NEWS = 0;
if (!modem_regs.reg1f.NEWS)
{
modem_regs.reg1f.NSIA = 0;
}
break;
default:
//printf("ModemNormalWrite : undef %03X=%X\n",reg,data);
break;
}
update_interrupt();
}
u32 ModemReadMem_A0_006(u32 addr, u32 size)
{
u32 reg=addr&0x7FF;
verify((reg&3)==0);
reg>>=2;
if (reg<0x100)
{
verify(reg<=1);
LOG("Reading MODEM ID addr %03x", reg);
return MODEM_ID[reg];
}
else
{
reg-=0x100;
if (reg<0x21)
{
if (state==MS_NORMAL)
{
// Dial tone is detected if TONEA, TONEB and TONEC are set
//if (reg==0xF)
{
SET_STATUS_BIT(0x0f, modem_regs.reg0f.CTS, modem_regs.reg08.RTS && connect_state == CONNECTED);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEA, connect_state == DISCONNECTED);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEB, connect_state == DISCONNECTED);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEC, connect_state == DISCONNECTED);
// FIXME This should be reset if transmit buffer is full
if (modem_regs.reg04.FIFOEN || module_download)
SET_STATUS_BIT(0x0d, modem_regs.reg0d.TXFNF, 1);
}
//LOG("Read reg %03x == %x", reg, modem_regs.ptr[reg]);
u8 data = modem_regs.ptr[reg];
if (reg == 0x00) // RBUFFER
{
//LOG("Read RBUFFER = %X", data);
modem_regs.reg1e.RDBF = 0;
SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 0);
if (connect_state == CONNECTED)
{
#ifndef RELEASE
if (recv_fp)
fputc(data, recv_fp);
#endif
// FIXME Code dup with sched_func
int c = read_pppd();
if (c >= 0)
{
//LOG("pppd received %02x", c);
#ifndef RELEASE
recvd_bytes++;
#endif
modem_regs.reg00 = c & 0xFF;
modem_regs.reg1e.RDBF = 1;
if (modem_regs.reg04.FIFOEN)
SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 1);
}
}
update_interrupt();
}
return data;
}
else if (state==MS_ST_CONTROLER || state==MS_ST_DSP)
{
if (reg==0x10)
{
modem_regs.reg1e.TDBE=0;
return 0;
}
else
{
//printf("modem reg %03X read -- reset/test state\n",reg);
return modem_regs.ptr[reg];
}
}
else if (state==MS_RESETING)
{
return 0; //still reset
}
else
{
LOG("Read (reset) reg %03x == %x", reg, modem_regs.ptr[reg]);
return modem_regs.ptr[reg];
}
}
else
{
LOG("modem reg %03X read -- wtf is it ?",reg);
return 0;
}
}
}
void ModemWriteMem_A0_006(u32 addr, u32 data, u32 size)
{
u32 reg=addr&0x7FF;
verify((reg&3)==0);
reg>>=2;
if (reg<0x100)
{
verify(reg<=1);
LOG("modem reg %03X write -- MODEM ID?!",reg);
}
else
{
reg-=0x100;
if (reg<0x20)
{
if (state==MS_NORMAL)
{
ModemNormalWrite(reg,data);
}
else
{
LOG("modem reg %03X write %X -- undef state?",reg,data);
}
return;
}
else if (reg==0x20)
{
//Hard reset
modem_reset(data);
}
else
{
LOG("modem reg %03X write %X -- wtf is it?",reg,data);
return;
}
}
}

28
core/hw/modem/modem.h Normal file
View File

@ -0,0 +1,28 @@
/*
Originally based on nullDC: nullExtDev/modem.h
Created on: Sep 9, 2018
Copyright 2018 skmp, flyinghead
This file is part of reicast.
reicast 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.
reicast 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 reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
u32 ModemReadMem_A0_006(u32 addr,u32 size);
void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size);

698
core/hw/modem/modem_regs.h Normal file
View File

@ -0,0 +1,698 @@
/*
Originally based on nullDC: nullExtDev/modem.cpp
Created on: Sep 9, 2018
Copyright 2018 skmp, flyinghead
This file is part of reicast.
reicast 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.
reicast 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 reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#pragma pack(1)
union modemreg_t
{
u8 ptr[0x21];
struct
{
//00 Receive Data Buffer (RBUFFER)/Voice Receive Data Buffer (VBUFR)
u8 reg00;
//01 VOLUME VPAUSE - - TXHF RXHF RXP
struct
{
u8 RXP:1;
u8 RXHF:1;
u8 TXHF:1;
u8 nil2:2;
u8 VPAUSE:1;
u8 VOLUME:2;
} reg01;
//02 TDE SQDIS S511 - RTSDE V54TE V54AE V54PE
// DCDEN CDEN - - CODBITS
struct
{
union
{
struct
{
u8 V54PE:1;
u8 V54AE:1;
u8 V54TE:1;
u8 RTSDE:1;
u8 nil1:1;
u8 S511:1;
} v0;
struct
{
u8 CODBITS:2;
u8 nil2:2;
u8 CDEN:1;
u8 DCDEN:1;
} v1;
struct
{
u8 nila:6;
u8 TDE:1;
u8 SQDIS:1;
};
};
} reg02;
//03 EPT SEPT SRCEN RLSDE - - GTE GTS
struct
{
u8 GTS:1;
u8 GTE:1;
u8 nil2:2;
u8 RLSDE:1;
u8 SRCEN:1;
u8 SEPT:1;
u8 EPT:1;
} reg03;
//04 RB - - FIFOEN - NRZIEN/VAGC TOD STRN
struct
{
u8 STRN:1;
u8 TOD:1;
u8 NRZIEN_VAGC:1;
u8 nil1_1:1;
u8 FIFOEN:1;
u8 nil1:2;
u8 RB:1;
} reg04;
//05 - - - TXSQ CEQ - STOFF -
struct
{
u8 nil1_2:1;
u8 STOFF:1;
u8 nil1_1:1;
u8 CEQ:1;
u8 TXSQ:1;
u8 nil1:3;
} reg05;
//06 - EXOS - HDLC PEN STB WDSZ/DECBITS
struct
{
u8 WDSZ_DECBITS:2;
u8 STB:1;
u8 PEN:1;
u8 HDLC:1;
u8 nil1_1:1;
u8 EXOS:1;
u8 nil1:1;
} reg06;
//07 RDLE RDL L2ACT - L3ACT - RA MHLD
struct
{
u8 MHLD:1;
u8 RA:1;
u8 nil1_1:1;
u8 L3ACT:1;
u8 nil1:1;
u8 L2ACT:1;
u8 RDL:1;
u8 RDLE:1;
} reg07;
//08 ASYN TPDM V21S V54T V54A V54P RTRN RTS
struct
{
u8 RTS:1;
u8 RTRN:1;
u8 V54P:1;
u8 V54A:1;
u8 V54T:1;
u8 V21S:1;
u8 TPDM:1;
u8 ASYN:1;
} reg08;
//09 NV25 CC DTMF ORG LL DATA RRTSE DTR
struct
{
u8 DTR:1;
u8 RRTSE:1;
u8 DATA:1;
u8 LL:1;
u8 ORG:1;
u8 DTMF:1;
u8 CC:1;
u8 NV25:1;
} reg09;
//0A PNSUC FLAGDT PE FE OE CRCS FLAGS SYNCD
struct
{
u8 SYNCD:1;
u8 FLAGS:1;
u8 CRCS:1;
u8 OE:1;
u8 FE:1;
u8 PE:1;
u8 FLAGDT:1;
u8 PNSUC:1;
} reg0a;
//0B TONEA TONEB TONEC ATV25 ATBEL - DISDET EQMAT
struct
{
u8 EQMAT:1;
u8 DISDET:1;
u8 nil:1;
u8 ATBEL:1;
u8 ATV25:1;
u8 TONEC:1;
u8 TONEB:1;
u8 TONEA:1;
} reg0b;
//0C AADET ACDET CADET CCDET SDET SNDET RXFNE RSEQ
struct
{
u8 RSEQ:1;
u8 RXFNE:1;
u8 SNDET:1;
u8 SDET:1;
u8 CCDET:1;
u8 CADET:1;
u8 ACDET:1;
u8 AADET:1;
} reg0c;
//0D P2DET PNDET S1DET SCR1 U1DET - TXFNF -
struct
{
u8 nil2:1;
u8 TXFNF:1;
u8 nil1:1;
u8 U1DET:1;
u8 SCR1:1;
u8 S1DET:1;
u8 PNDET:1;
u8 P2DET:1;
} reg0d;
//0E RTDET BRKD RREDT SPEED
struct
{
u8 SPEED:5;
u8 RREDT:1;
u8 BRKD:1;
u8 RTDET:1;
} reg0e;
//0F RLSD FED CTS DSR RI TM RTSDT V54DT
struct
{
u8 V54DT:1;
u8 RTSDT:1;
u8 TM:1;
u8 RI:1;
u8 DSR:1;
u8 CTS:1;
u8 FED:1;
u8 RLSD:1;
} reg0f;
//10 Transmit Data Buffer (TBUFFER)/Voice Transmit Buffer (VBUFT)
u8 reg10;
//11 BRKS PARSL TXV RXV V23HDX TEOF TXP
struct
{
u8 TXP:1;
u8 TEOF:1;
u8 V23HDX:1;
u8 RXV:1;
u8 TXV:1;
u8 PARSL:2;
u8 BRKS:1;
} reg11;
//12 Configuration (CONF)
u8 reg12;
//13 TLVL RTH TXCLK
struct
{
u8 TLVL:4;
u8 RTH:2;
u8 TXCLK:2;
} reg13;
//14 ABCODE
u8 reg14;
//15 SLEEP - RDWK HWRWK AUTO RREN EXL3 EARC
struct
{
u8 EARC:1;
u8 EXL3:1;
u8 RREN:1;
u8 AUTO:1;
u8 HWRWK:1;
u8 RDWK:1;
u8 STOP:1;
u8 SLEEP:1;
} reg15;
//16 Secondary Receive Data Buffer/V.34 Receive Status (SECRXB)
u8 reg16;
//17 Secondary Transmit Data Buffer/V.34 Transmit Status(SECTXB)
u8 reg17;
//18 Memory Access Data LSB B7-B0 (MEDAL)
//19 Memory Access Data MSB B15-B8 (MEDAM)
u16 reg18_19;
//1A SFRES RIEN RION DMAE - SCOBF SCIBE SECEN
struct
{
u8 SECEN:1;
u8 SCIBE:1;
u8 SCOBF:1;
u8 nil:1;
u8 DMAE:1;
u8 RION:1;
u8 RIEN:1;
u8 SFRES:1;
} reg1a;
//1B EDET DTDET OTS DTMFD DTMFW
struct
{
u8 DTMFW:4;
u8 DTMFD:1;
u8 OTS:1;
u8 DTDET:1;
u8 EDET:1;
} reg1b;
//1C Memory Access Address Low B7-B0 (MEADDL)
//1D MEACC - MEMW MEMCR Memory Access Address High B11-B8 (MEADDH)
struct
{
u8 MEMADD_l:8; //anything else exept u8 breaks it ? WTFH ?
u8 MEMADD_h:4;
u8 MEMCR:1;
u8 MEMW:1;
u8 nil:1;
u8 MEACC:1;
} reg1c_1d;
//1E TDBIA RDBIA TDBIE - TDBE RDBIE - RDBF
struct
{
u8 RDBF:1;
u8 nil:1;
u8 RDBIE:1;
u8 TDBE:1;
u8 nil2:1;
u8 TDBIE:1;
u8 RDBIA:1;
u8 TDBIA:1;
} reg1e;
//1F NSIA NCIA - NSIE NEWS NCIE - NEWC
struct
{
u8 NEWC:1;
u8 nil:1;
u8 NCIE:1;
u8 NEWS :1;
u8 NSIE:1;
u8 nil2:1;
u8 NCIA:1;
u8 NSIA:1;
} reg1f;
};
};
u8 regs_write_mask[] = {
//00 Receive Data Buffer (RBUFFER)/Voice Receive Data Buffer (VBUFR)
0xFF,
//01 VOLUME VPAUSE - - (TXHF RXHF RXP)
0xE0,
//02 TDE SQDIS S511 - RTSDE V54TE V54AE V54PE
// DCDEN CDEN - - CODBITS (ignored)
0xEF,
//03 EPT SEPT SRCEN RLSDE - - GTE GTS
0xF3,
//04 RB - - FIFOEN - NRZIEN/VAGC TOD STRN
0x95,
//05 - - - TXSQ CEQ - STOFF -
0x3A,
//06 - EXOS CCRTN HDLC PEN STB WDSZ/DECBITS
0x7F,
//07 RDLE RDL L2ACT - L3ACT - RA MHLD
0xEB,
//08 ASYN TPDM V21S V54T V54A V54P RTRN RTS
0xFF,
//09 NV25 CC DTMF ORG LL DATA RRTSE DTR
0xFF,
//0A (PNSUC FLAGDT PE FE) OE (CRCS FLAGS SYNCD)
0x08,
//0B (TONEA TONEB TONEC ATV25 ATBEL) - DISDET EQMAT
0x03,
//0C (AADET ACDET CADET CCDET SDET SNDET RXFNE) RSEQ
0x01,
//0D (P2DET PNDET S1DET SCR1 U1DET - TXFNF -)
0x00,
//0E (RTDET BRKD) RREDT (SPEED)
0x20,
//0F (RLSD FED CTS DSR RI TM) RTSDT V54DT
0x03,
//10 Transmit Data Buffer (TBUFFER)/Voice Transmit Buffer (VBUFT)
0xFF,
//11 BRKS PARSL TXV RXV V23HDX TEOF TXP
0xFF,
//12 Configuration (CONF)
0xFF,
//13 TLVL RTH TXCLK
0xFF,
//14 ABCODE
0xFF,
//15 SLEEP STOP RDWK HWRWK AUTO RREN EXL3 EARC
0xFF,
//16 Secondary Receive Data Buffer/V.34 Receive Status (SECRXB)
0xFF,
//17 Secondary Transmit Data Buffer/V.34 Transmit Status(SECTXB)
0xFF,
//18 Memory Access Data LSB B7-B0 (MEDAL)
0xFF,
//19 Memory Access Data MSB B15-B8 (MEDAM)
0xFF,
//1A SFRES RIEN RION DMAE - SCOBF SCIBE SECEN
0xF7,
//1B (EDET DTDET OTS DTMFD DTMFW)
0x00,
//1C Memory Access Address Low B7-B0 (MEADDL)
0xFF,
//1D MEACC - MEMW MEMCR Memory Access Address High B11-B8 (MEADDH)
0xBF,
//1E TDBIA RDBIA TDBIE - TDBE RDBIE - RDBF
0x24,
//1F NSIA NCIA - NSIE NEWS NCIE - NEWC
0x1D,
//20 reset
0xFF,
};
u32 regs_int_mask_addr[0x21] {
0,
0x247, // 01
0,
0,
0,
0,
0,
0,
0,
0,
0x246, // 0A
0x245, // 0B
0x244, // 0C
0x243, // 0D
0x242, // 0E
0x241, // 0F
0,
0,
0x089, // 12
0,
0x38a, // 14
0,
0x370, // 16
0x371, // 17
0,
0,
0x27d, // 1A
0x27c, // 1B
0,
};
// Power-on reset DSP RAM
static const u8 por_dspram[] =
{
/* 0x000 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0B0 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x130 */ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x140 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x150 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x170 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x180 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x190 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x200 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x210 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xAD, 0x08, 0x07, 0x99, 0x00, 0x23, 0xA0,
/* 0x220 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
/* 0x230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x240 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x250 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x260 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 26F Saved Filtered EQM (???)
/* 0x270 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x280 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00,
/* 0x290 */ 0x32, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x19, 0x85, 0x20, 0x00,
/* 0x2A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x2B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x2C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x2D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x2E0 */ 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // K56flex/V.34 Transmitter/Receiver Speed
/* 0x2F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x300 */ 0x00, 0x00, 0x00, 0x00, 0xC0, 0x28, 0x40, 0x03, 0x84, 0xCC, 0x00, 0x76, 0x84, 0xB1, 0x14, 0x02, // 304-8 V.8 Host Control Bits, 309-314 Modulation Modes
/* 0x310 */ 0x08, 0x08, 0xA4, 0xA4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x320 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x00, 0x00, // 32C: Receive FIFO Trigger Level
/* 0x330 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x340 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x350 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x360 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x370 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x380 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x390 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x3A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x3B0 */ 0x20, 0x1A, 0x12, 0x0C, 0x0A, 0x09, 0x05, 0x03, 0x02, 0x00, 0x90, 0x28, 0x10, 0x04, 0x01, 0x00, // ARA Thresholds
/* 0x3C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x3D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
/* 0x3E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x3F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x400 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x410 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x420 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x430 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x440 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x450 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x460 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x470 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x480 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x490 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x4F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x500 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x510 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x520 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x530 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x540 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x550 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x560 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x570 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x580 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x590 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x5F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x600 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x610 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x620 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x630 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x640 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x650 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x660 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x670 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x680 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x690 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x6F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x700 */ 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x710 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x720 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x730 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x740 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x750 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x760 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x770 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x780 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x790 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x7F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x800 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x810 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x820 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x830 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x840 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x850 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x860 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x870 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x880 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x890 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x8F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x900 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x910 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x920 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x930 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x940 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x950 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x960 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x970 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x980 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x990 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x9F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xAA0 */ 0x00, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0x00, 0x00,
/* 0xAB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xAC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xAD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xAE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xAF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xBF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC90 */ 0x00, 0x00, 0x00, 0x00, 0x1B, 0x2D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C96 Minimum Off Time (DTMF), C95 Positive Twist Control
/* 0xCA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xCB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xCC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xCD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xCE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xCF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xDF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E96 Minimum On Time (DTMF)
/* 0xEA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xEB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xEC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xED0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xEE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xEF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF20 */ 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F21 ADC Speech Sample Scaling Parameter
/* 0xF30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xFF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

159
core/hw/modem/pppd.cpp Normal file
View File

@ -0,0 +1,159 @@
/*
pppd.cpp
Created on: Sep 10, 2018
Copyright 2018 flyinghead
This file is part of reicast.
reicast 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 3 of the License, or
(at your option) any later version.
reicast 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 reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#if HOST_OS == OS_LINUX
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include "pppd.h"
static int pppd_pid;
static int inpipe = -1;
static int outpipe = -1;
static u8 in_buffer[128];
static int in_bufsize;
static int in_bufindex;
void start_pppd()
{
int inpipefd[2];
int outpipefd[2];
if (pipe(inpipefd) || pipe(outpipefd))
{
perror("pipe");
return;
}
pppd_pid = fork();
if (pppd_pid < 0)
{
perror("fork");
close(inpipefd[0]);
close(inpipefd[1]);
close(outpipefd[0]);
close(outpipefd[1]);
return;
}
if (pppd_pid == 0)
{
// Child
close(inpipefd[0]);
dup2(inpipefd[1], 1);
close(outpipefd[1]);
dup2(outpipefd[0], 0);
execl("/usr/sbin/pppd", "pppd", "notty", NULL);
perror("execl");
exit(1);
}
// Parent
inpipe = inpipefd[0];
outpipe = outpipefd[1];
fcntl(inpipe, F_SETFL, fcntl(inpipe, F_GETFL) | O_NONBLOCK);
}
void stop_pppd()
{
if (pppd_pid > 0)
{
kill(SIGTERM, pppd_pid);
// FIXME wait / waitpid
pppd_pid = 0;
}
if (inpipe >= 0)
{
close(inpipe);
inpipe = -1;
}
if (outpipe >= 0)
{
close(outpipe);
outpipe = -1;
}
}
void write_pppd(u8 b)
{
int rc = write(outpipe, &b, 1);
if (rc < 0)
perror("write outpipe");
else if (rc == 0)
printf("pppd EOF on outpipe\n");
}
int read_pppd()
{
if (in_bufindex == in_bufsize)
{
int rc = read(inpipe, in_buffer, sizeof(in_buffer));
if (rc < 0)
{
if (errno != EWOULDBLOCK)
perror("read inpipe");
return rc;
}
else if (rc == 0)
{
printf("pppd EOF on inpipe\n");
return -1;
}
in_bufsize = rc;
in_bufindex = 0;
}
return in_buffer[in_bufindex++];
}
int avail_pppd()
{
return in_bufsize - in_bufindex;
}
#else // not Linux
void start_pppd()
{
}
void stop_pppd()
{
}
void write_pppd(u8 b)
{
}
int read_pppd()
{
return -1;
}
int avail_pppd() {
return 0;
}
#endif

34
core/hw/modem/pppd.h Normal file
View File

@ -0,0 +1,34 @@
/*
pppd.h
Created on: Sep 10, 2018
Copyright 2018 flyinghead
This file is part of reicast.
reicast 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 3 of the License, or
(at your option) any later version.
reicast 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 reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CORE_HW_MODEM_PPPD_H_
#define CORE_HW_MODEM_PPPD_H_
#include "types.h"
void start_pppd();
void stop_pppd();
void write_pppd(u8 b);
int read_pppd();
int avail_pppd();
#endif /* CORE_HW_MODEM_PPPD_H_ */

View File

@ -841,8 +841,11 @@ s32 libExtDevice_Init();
void libExtDevice_Reset(bool M);
void libExtDevice_Term();
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
// 0x00600000 - 0x006007FF [Modem]
static u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) { return 0; }
static void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) { }
#endif
//Area 0 , 0x01000000- 0x01FFFFFF [Ext. Device]
static u32 libExtDevice_ReadMem_A0_010(u32 addr,u32 size) { return 0; }