* Add natfeat debugprintf support (dumps to the emu's stdout).

* Add XHDI disk support, unfinished.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23592 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol
2008-01-17 21:37:02 +00:00
parent 7014c8a379
commit d4d032389d
5 changed files with 508 additions and 75 deletions
@@ -53,6 +53,9 @@ dprintf(const char *format, ...)
Bconput(DEV_AUX, buffer);
// send to the emulator's stdout if available
nat_feat_debugprintf(buffer);
//if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
Bconput(DEV_CONSOLE, buffer);
}
+264 -29
View File
@@ -31,7 +31,7 @@ extern uint32 gBootPartitionOffset;
#define SCRATCH_SIZE (2*4096)
static uint8 gScratchBuffer[4096];
static const uint16 kParametersSizeVersion1 = sizeof(struct tosbpb);
static const uint16 kParametersSizeVersion1 = sizeof(struct tos_bpb);
static const uint16 kParametersSizeVersion2 = 0x1e;
static const uint16 kParametersSizeVersion3 = 0x42;
@@ -39,7 +39,7 @@ static const uint16 kDevicePathSignature = 0xbedd;
//XXX clean this up!
struct drive_parameters {
struct tosbpb bpb;
struct tos_bpb bpb;
uint16 parameters_size;
uint16 flags;
uint32 cylinders;
@@ -115,25 +115,22 @@ class BlockHandle : public Handle {
BlockHandle(int handle);
virtual ~BlockHandle();
status_t InitCheck() const;
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
virtual off_t Size() const;
virtual off_t Size() const { return fSize; };
uint32 BlockSize() const { return fBlockSize; }
status_t FillIdentifier();
bool HasParameters() const { return fHasParameters; }
const drive_parameters &Parameters() const { return fParameters; }
disk_identifier &Identifier() { return fIdentifier; }
uint8 DriveID() const { return fHandle; }
virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
protected:
status_t ReadBPB(struct tosbpb *bpb);
uint64 fSize;
uint32 fBlockSize;
bool fHasParameters;
@@ -142,15 +139,44 @@ class BlockHandle : public Handle {
};
class BIOSDrive : public BlockHandle {
public:
BIOSDrive(int handle);
virtual ~BIOSDrive();
status_t FillIdentifier();
virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
protected:
status_t ReadBPB(struct tos_bpb *bpb);
};
class XHDIDrive : public BlockHandle {
public:
XHDIDrive(int handle/*, uint16 major, uint16 minor ??*/);
virtual ~XHDIDrive();
status_t FillIdentifier();
virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
protected:
uint16 fMajor;
uint16 fMinor;
};
static bool sBlockDevicesAdded = false;
static status_t
read_bpb(uint8 drive, struct tosbpb *bpb)
read_bpb(uint8 drive, struct tos_bpb *bpb)
{
struct tosbpb *p;
struct tos_bpb *p;
p = Getbpb(drive);
memcpy(bpb, p, sizeof(struct tosbpb));
memcpy(bpb, p, sizeof(struct tos_bpb));
/* Getbpb is buggy so we must force a media change */
//XXX: docs seems to assume we should loop until it works
Mediach(drive);
@@ -401,6 +427,7 @@ add_block_devices(NodeList *devicesList, bool identifierMissing)
return B_OK;
map = Drvmap();
dprintf("Drvmap(): 0x%08lx\n", map);
for (driveID = 0; driveID < 32; driveID++) {
bool present = map & 0x1;
map >>= 1;
@@ -443,7 +470,108 @@ BlockHandle::BlockHandle(int handle)
: Handle(handle)
{
TRACE(("drive ID %u\n", fHandle));
}
BlockHandle::~BlockHandle()
{
}
status_t
BlockHandle::InitCheck() const
{
return fSize > 0 ? B_OK : B_ERROR;
}
ssize_t
BlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
ssize_t ret;
uint32 offset = pos % fBlockSize;
pos /= fBlockSize;
uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize;
int32 totalBytesRead = 0;
//TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu), drive %u\n",
// blocksLeft * fBlockSize, pos * fBlockSize, offset, fDriveID));
// read partial block
if (offset) {
ret = Rwabs(RW_READ | RW_NOTRANSLATE, gScratchBuffer, fBlockSize/256, -1, fHandle, pos * fBlockSize/256);
if (ret < 0)
return toserror(ret);
totalBytesRead += fBlockSize - offset;
memcpy(buffer, gScratchBuffer + offset, totalBytesRead);
}
uint32 scratchSize = SCRATCH_SIZE / fBlockSize;
while (blocksLeft > 0) {
uint32 blocksRead = blocksLeft;
if (blocksRead > scratchSize)
blocksRead = scratchSize;
ret = ReadBlocks(gScratchBuffer, pos, blocksRead);
if (ret < 0)
return ret;
uint32 bytesRead = fBlockSize * blocksRead - offset;
// copy no more than bufferSize bytes
if (bytesRead > bufferSize)
bytesRead = bufferSize;
memcpy(buffer, (void *)(gScratchBuffer + offset), bytesRead);
pos += blocksRead;
offset = 0;
blocksLeft -= blocksRead;
bufferSize -= bytesRead;
buffer = (void *)((addr_t)buffer + bytesRead);
totalBytesRead += bytesRead;
}
return totalBytesRead;
}
ssize_t
BlockHandle::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
// we don't have to know how to write
return B_NOT_ALLOWED;
}
ssize_t
BlockHandle::ReadBlocks(void *buffer, off_t first, int32 count)
{
return B_NOT_ALLOWED;
}
/*status_t
BlockHandle::FillIdentifier()
{
return B_NOT_ALLOWED;
}*/
// #pragma mark -
/*
* BIOS based disk access.
* Only for fallback from missing XHDI.
* XXX: This is broken!
* XXX: check for physical drives in PUN_INFO
* XXX: at least try to use MetaDOS calls instead.
*/
BIOSDrive::BIOSDrive(int handle)
: BlockHandle(handle)
{
/* first check if the drive exists */
/* note floppy B can be reported present anyway... */
uint32 map = Drvmap();
@@ -498,20 +626,13 @@ BlockHandle::BlockHandle(int handle)
}
BlockHandle::~BlockHandle()
BIOSDrive::~BIOSDrive()
{
}
status_t
BlockHandle::InitCheck() const
{
return fSize > 0 ? B_OK : B_ERROR;
}
ssize_t
BlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
BIOSDrive::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
int32 ret;
int sectorsPerBlocks = (fBlockSize / 256);
@@ -566,22 +687,15 @@ BlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
ssize_t
BlockHandle::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
BIOSDrive::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
// we don't have to know how to write
return B_NOT_ALLOWED;
}
off_t
BlockHandle::Size() const
{
return fSize;
}
status_t
BlockHandle::FillIdentifier()
BIOSDrive::FillIdentifier()
{
#if 0
if (HasParameters()) {
@@ -621,6 +735,127 @@ BlockHandle::FillIdentifier()
}
ssize_t
BIOSDrive::ReadBlocks(void *buffer, off_t first, int32 count)
{
int sectorsPerBlocks = (fBlockSize / 256);
int32 ret;
// XXX: check for AHDI 3.0 before using long recno!!!
ret = Rwabs(RW_READ | RW_NOTRANSLATE, buffer, sectorsPerBlocks, -1, fHandle, first * sectorsPerBlocks);
if (ret < 0)
return toserror(ret);
return ret;
}
// #pragma mark -
/*
* XHDI based devices
*/
XHDIDrive::XHDIDrive(int handle)
: BlockHandle(handle)
{
/* first check if the drive exists */
/* note floppy B can be reported present anyway... */
uint32 map = Drvmap();
if (!(map & (1 << fHandle))) {
fSize = 0LL;
return;
}
//XXX: check size
if (get_drive_parameters(fHandle, &fParameters) != B_OK) {
dprintf("getting drive parameters for: %u failed!\n", fHandle);
return;
}
fBlockSize = 512;
fSize = fParameters.sectors * fBlockSize;
fHasParameters = false;
#if 0
if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
// old style CHS support
if (get_drive_parameters(driveID, &fParameters) != B_OK) {
dprintf("getting drive parameters for: %u failed!\n", fDriveID);
return;
}
TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
fParameters.bytes_per_sector));
TRACE((" total sectors: %Ld\n", fParameters.sectors));
fBlockSize = 512;
fSize = fParameters.sectors * fBlockSize;
fLBA = false;
fHasParameters = false;
} else {
TRACE(("size: %x\n", fParameters.parameters_size));
TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
fParameters.interface_type));
TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
fParameters.bytes_per_sector));
TRACE(("total sectors: %Ld\n", fParameters.sectors));
fBlockSize = fParameters.bytes_per_sector;
fSize = fParameters.sectors * fBlockSize;
fLBA = true;
fHasParameters = true;
}
#endif
}
XHDIDrive::~XHDIDrive()
{
}
status_t
XHDIDrive::FillIdentifier()
{
fIdentifier.bus_type = UNKNOWN_BUS;
fIdentifier.device_type = UNKNOWN_DEVICE;
fIdentifier.device.unknown.size = Size();
#if 0
// cf. http://toshyp.atari.org/010008.htm#XHDI-Terminologie
if (fMajor >= 8 && fMajor <= 15) { // scsi
fIdentifier.device_type = SCSI_DEVICE;
fIdentifier.device.scsi.logical_unit = fMinor;
//XXX: where am I supposed to put the ID ???
}
#endif
for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
fIdentifier.device.unknown.check_sums[i].offset = -1;
fIdentifier.device.unknown.check_sums[i].sum = 0;
}
#endif
return B_ERROR;
}
ssize_t
XHDIDrive::ReadBlocks(void *buffer, off_t first, int32 count)
{
int sectorsPerBlocks = (fBlockSize / 256);
int32 ret;
uint16 flags = RW_READ;
//ret = XHReadWrite(fMajor, fMinor, flags, buffer, (uint32)first, (uint16)count, buffer);
if (ret < 0)
return toserror(ret);
return ret;
}
// #pragma mark -
@@ -118,6 +118,9 @@ _start(void)
// call C++ constructors before doing anything else
args.heap_size = HEAP_SIZE;
// so we can dprintf
init_nat_features();
//serial_init();
console_init();
@@ -12,6 +12,9 @@
#include <Errors.h>
void *gXHDIEntryPoint = NULL;
NatFeatCookie *gNatFeatCookie = NULL;
int32 gDebugPrintfNatFeatID = 0;
/*! Maps TOS error codes to native errors
*/
@@ -103,6 +106,60 @@ toserror(int32 err)
}
/*! Maps XHDI error codes to native errors
* cf. http://toshyp.atari.org/010008.htm#XHDI_20error_20codes
*/
status_t
xhdierror(int32 err)
{
if (err <= -456) {
int ide = -(err + 456);
// ide status reg
// guessed mapping
if (ide & (1 << 1)) { // track 0 not found
return B_DEV_FORMAT_ERROR;
} else if (ide & (1 << 0)) { // DAM not found
return B_DEV_FORMAT_ERROR,;
} else if (ide & (1 << 4)) { // ID field not found
return B_DEV_ID_ERROR;
} else if (ide & (1 << 7)) { // bad block mark
return B_DEV_FORMAT_ERROR;
} else if (ide & (1 << 6)) { // uncorrectable error
return B_DEV_UNREADABLE;
} else if (ide & (1 << 2)) { // command aborted
return EINTR;
} else if (ide & (1 << 5)) { // media change
return B_DEV_MEDIA_CHANGED;
} else if (ide & (1 << 3)) { // media change requested
return B_DEV_MEDIA_CHANGE_REQUESTED;
}
return B_ERROR;
} else if (err <= -200) {
/* SCSI errors */
int scsi = -(err + 200);
//XXX:
switch (scsi) {
case 0x06:
return B_DEV_FORMAT_ERROR;
case 0x10:
return B_DEV_FORMAT_ERROR;
case 0x11:
return B_DEV_UNREADABLE;
case 0x12:
return B_DEV_ID_ERROR;
case 0x13:
return B_DEV_FORMAT_ERROR;
case 0x20:
return EINTR;
case 0x28:
return B_DEV_FORMAT_ERROR;
case 0x5a:
return B_DEV_FORMAT_ERROR;
}
}
return toserror(err);
}
void
dump_tos_cookie(const struct tos_cookie *c)
{
@@ -121,3 +178,28 @@ dump_tos_cookies(void)
}
}
status_t
init_xhdi(void)
{
}
status_t
init_nat_features(void)
{
if (nat_features()) {
// find debugprintf id
gDebugPrintfNatFeatID = nat_feat_getid("DEBUGPRINTF");
//
}
return nat_features() ? B_OK : ENOENT;
}
void
nat_feat_debugprintf(const char *str)
{
if (gDebugPrintfNatFeatID)
nat_feat_call(gDebugPrintfNatFeatID, 0, str);
}
+156 -46
View File
@@ -27,40 +27,40 @@ extern "C" {
//#endif
/* void (no) arg */
#define toscallV(trapnr, callnr) \
({ \
#define toscallV(trapnr, callnr) \
({ \
register int32 retvalue __asm__("d0"); \
\
__asm__ volatile \
("/* toscall(" #trapnr ", " #callnr ") */\n \
move.w %[calln],-(%%sp)\n \
trap %[trapn]\n \
add.l #2,%%sp\n" \
: "=r"(retvalue) /* output */ \
\
__asm__ volatile \
("/* toscall(" #trapnr ", " #callnr ") */\n" \
" move.w %[calln],-(%%sp)\n" \
" trap %[trapn]\n" \
" add.l #2,%%sp\n" \
: "=r"(retvalue) /* output */ \
: [trapn]"i"(trapnr),[calln]"i"(callnr) \
/* input */ \
/* input */ \
: TOS_CLOBBER_LIST /* clobbered regs */ \
); \
retvalue; \
); \
retvalue; \
})
#define toscallW(trapnr, callnr, p1) \
({ \
({ \
register int32 retvalue __asm__("d0"); \
int16 _p1 = (int16)(p1); \
\
__asm__ volatile \
("/* toscall(" #trapnr ", " #callnr ") */\n \
move.w %1,-(%%sp) \n \
move.w %[calln],-(%%sp)\n \
trap %[trapn]\n \
add.l #4,%%sp \n " \
: "=r"(retvalue) /* output */ \
: "r"(_p1), /* input */ \
int16 _p1 = (int16)(p1); \
\
__asm__ volatile \
("/* toscall(" #trapnr ", " #callnr ") */\n" \
" move.w %1,-(%%sp) \n" \
" move.w %[calln],-(%%sp)\n" \
" trap %[trapn]\n" \
" add.l #4,%%sp \n" \
: "=r"(retvalue) /* output */ \
: "r"(_p1), /* input */ \
[trapn]"i"(trapnr),[calln]"i"(callnr) \
: TOS_CLOBBER_LIST /* clobbered regs */ \
); \
retvalue; \
); \
retvalue; \
})
#define toscallL(trapnr, callnr, p1) \
@@ -182,7 +182,7 @@ extern "C" {
// cf. http://www.fortunecity.com/skyscraper/apple/308/html/bios.htm
struct tosbpb {
struct tos_bpb {
int16 recsiz;
int16 clsiz;
int16 clsizb;
@@ -194,6 +194,18 @@ struct tosbpb {
int16 bflags;
};
struct tos_pun_info {
int16 puns;
uint8 pun[16];
int32 part_start[16]; // unsigned ??
uint32 p_cookie;
struct tos_pun_info *p_cooptr; // points to itself
uint16 p_version;
uint16 p_max_sector;
int32 reserved[16];
};
#define PUN_INFO ((struct tos_pun_info *)0x516L)
//#define Getmpb() toscallV(BIOS_TRAP, 0)
#define Bconstat(dev) toscallW(BIOS_TRAP, 1, (uint16)dev)
@@ -202,7 +214,7 @@ struct tosbpb {
#define Rwabs(mode, buf, count, recno, dev, lrecno) toscallWPWWWL(BIOS_TRAP, 4, (int16)mode, (void *)buf, (int16)count, (int16)recno, (uint16)dev, (int32)lrecno)
//#define Setexc() toscallV(BIOS_TRAP, 5, )
#define Tickcal() toscallV(BIOS_TRAP, 6)
#define Getbpb(dev) (struct tosbpb *)toscallW(BIOS_TRAP, 7, (uint16)dev)
#define Getbpb(dev) (struct tos_bpb *)toscallW(BIOS_TRAP, 7, (uint16)dev)
#define Bcostat(dev) toscallW(BIOS_TRAP, 8, (uint16)dev)
#define Mediach(dev) toscallW(BIOS_TRAP, 9, (int16)dev)
#define Drvmap() (uint32)toscallV(BIOS_TRAP, 10)
@@ -312,12 +324,119 @@ static inline int Bconputs(int16 handle, const char *string)
#ifndef __ASSEMBLER__
/*
* MetaDOS XBIOS calls
*/
//#define _DISABLE 0
#ifndef __ASSEMBLER__
#define Metainit(buf) toscallP(XBIOS_TRAP, 48, (void *)buf)
#define Metaopen(drive, p) toscall>P(XBIOS_TRAP, 48, (void *)buf)
#define Metaclose(drive) toscallW(XBIOS_TRAP, 50, (int16)drive)
#define Metagettoc(drive, flag, p) toscallW(XBIOS_TRAP, 62, (int16)drive, (int16)flag, (void *)p)
#define Metadiscinfo(drive, p) toscallWP(XBIOS_TRAP, 63, (int16)drive, (void *)p)
#define Metaioctl(drive, magic, op, buf) toscallWLWP(XBIOS_TRAP, 55, (int16)drive, (int32)magic, (int16)op, )
//#define Meta(drive) toscallW(XBIOS_TRAP, 50, (int16)drive)
//#define Meta(drive) toscallW(XBIOS_TRAP, 50, (int16)drive)
//#define Meta(drive) toscallW(XBIOS_TRAP, 50, (int16)drive)
#endif /* __ASSEMBLER__ */
/*
* XHDI support
* see http://toshyp.atari.org/010008.htm
*/
#define XHDI_COOKIE 'XHDI'
#define XHDI_MAGIC 0x27011992
#define XHDI_CLOBBER_LIST /* only d0 */
#define XH_TARGET_STOPPABLE 0x00000001L
#define XH_TARGET_REMOVABLE 0x00000002L
#define XH_TARGET_LOCKABLE 0x00000004L
#define XH_TARGET_EJECTABLE 0x00000008L
#define XH_TARGET_LOCKED 0x20000000L
#define XH_TARGET_STOPPED 0x40000000L
#define XH_TARGET_RESERVED 0x80000000L
#ifndef __ASSEMBLER__
/* pointer to the XHDI dispatch function */
extern void *gXHDIEntryPoint;
/* void (no) arg */
#define xhdicallV(callnr) \
({ \
register int32 retvalue __asm__("d0"); \
\
__asm__ volatile \
("/* xhdicall(" #callnr ") */\n" \
" move.w %[calln],-(%%sp)\n" \
" call (%[entry])\n" \
" add.l #2,%%sp\n" \
: "=r"(retvalue) /* output */ \
: /* input */ \
[entry]"a"(gXHDIEntryPoint), \
[calln]"i"(callnr) \
: XHDI_CLOBBER_LIST /* clobbered regs */ \
); \
retvalue; \
})
#define xhdicallW(callnr, p1) \
({ \
register int32 retvalue __asm__("d0"); \
int16 _p1 = (int16)(p1); \
\
__asm__ volatile \
("/* xhdicall(" #callnr ") */\n" \
" move.w %1,-(%%sp) \n" \
" move.w %[calln],-(%%sp)\n" \
" call (%[entry])\n" \
" add.l #4,%%sp \n" \
: "=r"(retvalue) /* output */ \
: "r"(_p1), /* input */ \
[entry]"a"(gXHDIEntryPoint), \
[calln]"i"(callnr) \
: XHDI_CLOBBER_LIST /* clobbered regs */ \
); \
retvalue; \
})
#define XHGetVersion() (uint16)xhdicallV(0)
#define XHInqTarget(major, minor, bsize, flags, pname) xhdicallWWPPP(1, (uint16)major, (uint16)minor, (uint32 *)bsize, (uint32 *)flags, (char *)pname)
//XHReserve 2
//#define XHLock() 3
//#define XHStop() 4
#define XHEject(major, minor, doeject, key) xhdicallWWWW(5, (uint16)major, (uint16)minor, (uint16)doeject, (uint16)key)
#define XHDrvMap() xhdicallV(6)
//#define XHInqDev(dev,) xhdicall(7,)
//XHInqDriver 8
//XHNewCookie 9
#define XHReadWrite(major, minor, rwflags, recno, count, buf) xhdicalWWWLWP(10, (uint16)major, (uint16)minor, (uint16)rwflags, (uint32)recno, (uint16)count, (void *)buf)
#define XHInqTarget2(major, minor, bsize, flags, pname, pnlen) xhdicallWWPPPW(11, (uint16)major, (uint16)minor, (uint32 *)bsize, (uint32 *)flags, (char *)pname, (uint16)pnlen)
//XHInqDev2 12
//XHDriverSpecial 13
#define XHGetCapacity(major, minor, blocks, blocksize) xhdicall(14, (uint16)major, (uint16)minor, (uint32 *)blocks, (uint32 *)blocksize)
//#define XHMediumChanged() 15
//XHMiNTInfo 16
//XHDosLimits 17
//XHLastAccess 18
//SHReaccess 19
#endif /* __ASSEMBLER__ */
/*
* error mapping
* in debug.c
*/
extern status_t toserror(int32 err);
extern status_t xhdierror(int32 err);
extern void dump_tos_cookies(void);
/*
@@ -374,10 +493,6 @@ static inline const struct tos_osheader *tos_get_osheader()
#endif /* __ASSEMBLER__ */
/*
* XHDI
*/
/*
* ARAnyM Native Features
*/
@@ -388,18 +503,21 @@ static inline const struct tos_osheader *tos_get_osheader()
#ifndef __ASSEMBLER__
typedef struct {
long magic;
long (*nfGetID) (const char *);
long (*nfCall) (long ID, ...);
uint32 magic;
int32 (*nfGetID) (const char *);
int32 (*nfCall) (int32 ID, ...);
} NatFeatCookie;
extern NatFeatCookie *gNatFeatCookie;
extern int32 gDebugPrintfNatFeatID;
static inline NatFeatCookie *nat_features(void)
{
const struct tos_cookie *c;
if (gNatFeatCookie == (void *)-1 || !gNatFeatCookie)
if (gNatFeatCookie == (void *)-1)
return NULL;
if (gNatFeatCookie)
return gNatFeatCookie;
c = tos_find_cookie(NF_COOKIE);
if (c) {
gNatFeatCookie = (NatFeatCookie *)c->pvalue;
@@ -411,6 +529,8 @@ static inline NatFeatCookie *nat_features(void)
return NULL;
}
extern status_t init_nat_features(void);
static inline int32 nat_feat_getid(const char *name)
{
NatFeatCookie *c = nat_features();
@@ -429,17 +549,7 @@ static inline int32 nat_feat_getid(const char *name)
ret; \
})
/* XHDI NatFeat */
#define NF_XHDI "XHDI"
#define nfxhdi(code, a...) \
({ \
gNatFeatCookie->nfCall((uint32)code, a##...); \
})
#define NFXHversion() nfxhdi(0)
extern void nat_feat_debugprintf(const char *str);
#endif /* __ASSEMBLER__ */