/**
 * DreamShell luaKOS
 * Using all functions with prefix - "KOS."
 *
 */

// for lua
size_t *size_t_new();
void size_t_delete(size_t *s);


/* Flush a range of i-cache, given a physical address range */
void icache_flush_range(uint32 start, uint32 count);

/* Invalidate a range of o-cache/d-cache, given a physical address range */
void dcache_inval_range(uint32 start, uint32 count);

/* Flush a range of o-cache/d-cache, given a physical address range */
void dcache_flush_range(uint32 start, uint32 count);

/* Replace the currently running image with whatever is at
   the pointer; note that this call will never return. */
void arch_exec_at(const void *image, uint32 length, uint32 address);
void arch_exec(const void *image, uint32 length);


/* Directory entry; all handlers must conform to this interface */
typedef struct kos_dirent {
	int	size;
	char	name[MAX_FN_LEN];
	time_t	time;
	uint32	attr;
} dirent_t;

/* File status information; like dirent, this is not the same as the *nix
   variation but it has similar information. */
struct vfs_handler;
typedef struct /*stat*/ {
	struct vfs_handler	* dev;		/* The VFS handler for this file/dir */
	uint32			unique;		/* A unique identifier on the VFS for this file/dir */
	uint32			type;		/* File/Dir type */
	uint32			attr;		/* Attributes */
	off_t			size;		/* Total file size, if applicable */
	time_t			time;		/* Last access/mod/change time (depends on VFS) */
} stat_t;

/* stat_t.unique */
#define STAT_UNIQUE_NONE	0	/* Constant to use denoting the file has no unique ID */

/* stat_t.type */
#define STAT_TYPE_NONE		0	/* Unknown / undefined / not relevant */
#define STAT_TYPE_FILE		1	/* Standard file */
#define STAT_TYPE_DIR		2	/* Standard directory */
#define STAT_TYPE_PIPE		3	/* A virtual device of some sort (pipe, socket, etc) */
#define STAT_TYPE_META		4	/* Meta data */

/* stat_t.attr */
#define STAT_ATTR_NONE		0x00	/* No attributes */
#define STAT_ATTR_R		0x01	/* Read-capable */
#define STAT_ATTR_W		0x02	/* Write-capable */
//#define STAT_ATTR_RW		(STAT_ATTR_R | STAT_ATTR_W)	/* Read/Write capable */

/* File descriptor type */
typedef int file_t;

/* Invalid file handle constant (for open failure, etc) */
//#define FILEHND_INVALID	((file_t)-1)

/* This is the number of distinct file descriptors the global table
   has in it. */
#define FD_SETSIZE	1024

/* This is the private struct that will be used as raw file handles
   underlying descriptors. */
struct fs_hnd;

/* The kernel-wide file descriptor table. These will reference to open files. */
//extern struct fs_hnd * fd_table[FD_SETSIZE];

/* Open modes */
//#include <sys/fcntl.h>
//#if 0
#define O_RDONLY	1		/* Read only */
#define O_RDWR		2		/* Read-write */
#define O_APPEND	3		/* Append to an existing file */
#define O_WRONLY	4		/* Write-only */
//#endif
//#define O_MODE_MASK	7		/* Mask for mode numbers */
#define O_MODE_MASK	0x0f		/* Mask for mode numbers */
#define O_TRUNC		0x0100		/* Truncate */
#define O_ASYNC		0x0200		/* Open for asynchronous I/O */
#define O_NONBLOCK	0x0400		/* Open for non-blocking I/O */
#define O_DIR		0x1000		/* Open as directory */
#define O_META		0x2000		/* Open as metadata */

/* Seek modes */
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2

/* Standard file descriptor functions */
file_t	fs_open(const char *fn, int mode);
void	fs_close(file_t hnd);
ssize_t	fs_read(file_t hnd, void *buffer, size_t cnt);
ssize_t	fs_write(file_t hnd, const void *buffer, size_t cnt);
off_t	fs_seek(file_t hnd, off_t offset, int whence);
off_t	fs_tell(file_t hnd);
size_t	fs_total(file_t hnd);
dirent_t* fs_readdir(file_t hnd);
int	fs_ioctl(file_t hnd, void *data, size_t size);
int	fs_rename(const char *fn1, const char *fn2);
int	fs_unlink(const char *fn);
int	fs_chdir(const char *fn);
void*	fs_mmap(file_t hnd);
int	fs_complete(file_t fd, ssize_t * rv);
int	fs_stat(const char * fn, stat_t * rv);
int	fs_mkdir(const char * fn);
int	fs_rmdir(const char * fn);
file_t	fs_dup(file_t oldfd);
file_t	fs_dup2(file_t oldfd, file_t newfd);

/* Call this function to create a "transient" file descriptor. What this
   does for you is let you setup ad-hoc VFS integration for libs that
   have their own open mechanism (e.g., TCP/IP sockets). It could also be
   used to do things like generic resource management. Calling this
   function is functionally identical to fs_open, except it doesn't
   require registering a full VFS or doing a name lookup. */
file_t	fs_open_handle(vfs_handler_t * vfs, void * hnd);

/* These two functions are used to reveal "internal" info about a file
   descriptor, so that libraries can provide their own facilities using
   VFS-sponsored file descriptors (e.g., TCP/IP bind, connect, etc). */
vfs_handler_t * fs_get_handler(file_t fd);
void * fs_get_handle(file_t fd);

/* Returns the working directory of the current thread */
const char *fs_getwd();

/* Couple of util functions */

/* Copies a file from 'src' to 'dst'. The amount of the file
   actually copied without error is returned. */
ssize_t	fs_copy(const char * src, const char * dst);

/* Opens a file, allocates enough RAM to hold the whole thing,
   reads it into RAM, and closes it. The caller owns the allocated
   memory (and must free it). The file size is returned, or -1
   on failure; on success, out_ptr is filled with the address
   of the loaded buffer, and on failure it is set to NULL. */
ssize_t fs_load(const char * src, void ** out_ptr);


/* Call this function to create a new pty. The name of the pty is written
   into the user-provided buffer (if non-NULL) and two open file descriptors
   pointing to the two ends of the pty are returned. */
int fs_pty_create(char * buffer, int maxbuflen, file_t * master_out, file_t * slave_out);



/* DMA copy from SH-4 RAM to G2 bus (dir = 0) or the opposite;
   length must be a multiple of 32,
   and the source and destination addresses must be aligned on 32-byte
   boundaries. If block is non-zero, this function won't return until
   the transfer is complete. If callback is non-NULL, it will be called
   upon completion (in an interrupt context!). Returns <0 on error.

   Known working combination :

   g2chn = 0, sh4chn = 3 --> mode = 5 (but many other value seems OK ?)
   g2chn = 1, sh4chn = 1 --> mode = 0 (or 4 better ?)
   g2chn = 1, sh4chn = 0 --> mode = 3

   It seems that g2chn is not important when choosing mode, so this mode parameter is probably
   how we actually connect the sh4chn to the g2chn.

   Update : looks like there is a formula, mode = 3 + shchn

*/

/* We use sh channel 3 here to avoid conflicts with the PVR. */
#define SPU_DMA_MODE   6 /* should we use 6 instead, so that the formula is 3+shchn ?
			    6 works too, so ... */
#define SPU_DMA_G2CHN  0
#define SPU_DMA_SHCHN  3

/* For BBA : sh channel 1 (doesn't seem used) and g2 channel 1 to no conflict with SPU */
#define BBA_DMA_MODE   4
#define BBA_DMA_G2CHN  1
#define BBA_DMA_SHCHN  1

/* For BBA2 : sh channel 0 (doesn't seem used) and g2 channel 2 to no conflict with SPU */
/* This is a second DMA channels used for the BBA, just for fun and see if we can initiate
   two DMA transfers with the BBA concurently. */
#define BBA_DMA2_MODE   3
#define BBA_DMA2_G2CHN  2
#define BBA_DMA2_SHCHN  0

//typedef void (*g2_dma_callback_t)(ptr_t data);
//int g2_dma_transfer(void *from, void * dest, uint32 length, int block,
//	g2_dma_callback_t callback, ptr_t cbdata,
//	uint32 dir, uint32 mode, uint32 g2chn, uint32 sh4chn);

/* Read one byte from G2 */
uint8 g2_read_8(uint32 address);

/* Write one byte to G2 */
void g2_write_8(uint32 address, uint8 value);

/* Read one word from G2 */
uint16 g2_read_16(uint32 address);

/* Write one word to G2 */
void g2_write_16(uint32 address, uint16 value);

/* Read one dword from G2 */
uint32 g2_read_32(uint32 address);

/* Write one dword to G2 */
void g2_write_32(uint32 address, uint32 value);

/* Read a block of 8-bit values from G2 */
void g2_read_block_8(uint8 * output, uint32 address, int amt);

/* Write a block 8-bit values to G2 */
void g2_write_block_8(const uint8 * input, uint32 address, int amt);

/* Read a block of 16-bit values from G2 */
void g2_read_block_16(uint16 * output, uint32 address, int amt);

/* Write a block of 16-bit values to G2 */
void g2_write_block_16(const uint16 * input, uint32 address, int amt);

/* Read a block of 32-bit values from G2 */
void g2_read_block_32(uint32 * output, uint32 address, int amt);

/* Write a block of 32-bit values to G2 */
void g2_write_block_32(const uint32 * input, uint32 address, int amt);

/* When writing to the SPU RAM, this is required at least every 8 32-bit
   writes that you execute */
void g2_fifo_wait();


#define MODEM_SPEED_AUTO  0x0
#define MODEM_SPEED_1200  0x0
#define MODEM_SPEED_2400  0x1
#define MODEM_SPEED_4800  0x2
#define MODEM_SPEED_7200  0x3
#define MODEM_SPEED_9600  0x4
#define MODEM_SPEED_12000 0x5
#define MODEM_SPEED_14400 0x6
#define MODEM_SPEED_16800 0x7
#define MODEM_SPEED_19200 0x8
#define MODEM_SPEED_21600 0x9
#define MODEM_SPEED_24000 0xA
#define MODEM_SPEED_26400 0xB
#define MODEM_SPEED_28000 0xC
#define MODEM_SPEED_31200 0xD
#define MODEM_SPEED_33600 0xE

/* Protocols */
#define MODEM_PROTOCOL_V17    0x0
#define MODEM_PROTOCOL_V22    0x1
#define MODEM_PROTOCOL_V22BIS 0x2
#define MODEM_PROTOCOL_V32    0x3
#define MODEM_PROTOCOL_V32BIS 0x4
#define MODEM_PROTOCOL_V34    0x5
#define MODEM_PROTOCOL_V8     0x6


#define MODEM_MODE_REMOTE 0   /* Connect to a remote modem */
#define MODEM_MODE_ANSWER 1   /* Answer a call when a ring is detected */
#define MODEM_MODE_NULL   255 /* Not doing anything. Don't give this to
                                 any function! */

/* V.22 bis modes */
#define MODEM_SPEED_V22BIS_1200 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V22BIS, MODEM_SPEED_1200)
#define MODEM_SPEED_V22BIS_2400 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V22BIS, MODEM_SPEED_2400)

/* V.22 modes */
#define MODEM_SPEED_V22_1200 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V22, MODEM_SPEED_1200)

/* V.32 modes */
#define MODEM_SPEED_V32_4800 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V32, MODEM_SPEED_4800)
#define MODEM_SPEED_V32_9600 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V32, MODEM_SPEED_9600)

/* V.32 bis modes */
#define MODEM_SPEED_V32BIS_7200  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V32BIS, MODEM_SPEED_7200)
#define MODEM_SPEED_V32BIS_12000 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V32BIS, MODEM_SPEED_12000)
#define MODEM_SPEED_V32BIS_14400 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V32BIS, MODEM_SPEED_14400)

/* V.8 modes */
#define MODEM_SPEED_V8_2400  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_2400)
#define MODEM_SPEED_V8_4800  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_4800)
#define MODEM_SPEED_V8_7200  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_7200)
#define MODEM_SPEED_V8_9600  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_9600)
#define MODEM_SPEED_V8_12000 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_12000)
#define MODEM_SPEED_V8_14400 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_14400)
#define MODEM_SPEED_V8_16800 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_16800)
#define MODEM_SPEED_V8_19200 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_19200)
#define MODEM_SPEED_V8_21600 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_21600)
#define MODEM_SPEED_V8_24000 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_24000)
#define MODEM_SPEED_V8_26400 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_26400)
#define MODEM_SPEED_V8_28000 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_28000)
#define MODEM_SPEED_V8_31200 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_31200)
#define MODEM_SPEED_V8_33600 MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_33600)
#define MODEM_SPEED_V8_AUTO  MODEM_MAKE_SPEED(MODEM_PROTOCOL_V8, MODEM_SPEED_1200)

/* Event constants */
//typedef enum
//{
//    MODEM_EVENT_CONNECTION_FAILED = 0, /* The modem tried to establish a connection but failed */
//    MODEM_EVENT_CONNECTED,             /* A connection has been established */
//    MODEM_EVENT_DISCONNECTED,          /* The remote modem dropped the connection */
//    MODEM_EVENT_RX_NOT_EMPTY,          /* New data has entered the previously empty receive buffer */
//    MODEM_EVENT_OVERFLOW,              /* The receive buffer overflowed and was cleared */
//    MODEM_EVENT_TX_EMPTY               /* The transmission buffer has been emptied */
//} modemEvent_t;

//typedef void (*MODEMEVENTHANDLERPROC)(modemEvent_t event);


int           modem_init(void);
void          modem_shutdown(void);
int           modem_set_mode(int mode, modem_speed_t speed);
int           modem_wait_dialtone(int ms_timeout);
int           modem_dial(const char *digits);
//void          modem_set_event_handler(MODEMEVENTHANDLERPROC eventHandler);
void          modem_disconnect(void);
int           modem_is_connecting(void);
int           modem_is_connected(void);
unsigned long modem_get_connection_rate(void);

int modem_read_data(unsigned char *data, int size);
int modem_write_data(unsigned char *data, int size);
int modem_has_data(void);


/* Set serial parameters; this is not platform independent like I want
   it to be, but it should be generic enough to be useful. */
void scif_set_parameters(int baud, int fifo);

// The rest of these are the standard dbgio interface.
int scif_set_irq_usage(int on);
int scif_detected();
int scif_init();
int scif_shutdown();
int scif_read();
int scif_write(int c);
int scif_flush();
int scif_write_buffer(const uint8 *data, int len, int xlat);
int scif_read_buffer(uint8 *data, int len);



#define CMD_PIOREAD 16  /**< \brief Read via PIO */
#define CMD_DMAREAD 17  /**< \brief Read via DMA */
#define CMD_GETTOC  18  /**< \brief Read TOC */
#define CMD_GETTOC2 19  /**< \brief Read TOC */
#define CMD_PLAY    20  /**< \brief Play track */
#define CMD_PLAY2   21  /**< \brief Play sectors */
#define CMD_PAUSE   22  /**< \brief Pause playback */
#define CMD_RELEASE 23  /**< \brief Resume from pause */
#define CMD_INIT    24  /**< \brief Initialize the drive */
#define CMD_SEEK    27  /**< \brief Seek to a new position */
#define CMD_READ    28  /**< \brief Read raw sectors */
#define CMD_STOP    33  /**< \brief Stop the disc from spinning */
#define CMD_GETSCD  34  /**< \brief Get subcode data */
#define CMD_GETSES  35  /**< \brief Get session */
/** @} */

/** \defgroup cd_cmd_response       CD-ROM command responses

    These are the values that the various functions can return as error codes.
    @{
*/
#define ERR_OK          0   /**< \brief No error */
#define ERR_NO_DISC     1   /**< \brief No disc in drive */
#define ERR_DISC_CHG    2   /**< \brief Disc changed, but not reinitted yet */
#define ERR_SYS         3   /**< \brief System error */
#define ERR_ABORTED     4   /**< \brief Command aborted */
#define ERR_NO_ACTIVE   5   /**< \brief System inactive? */
/** @} */

/** \defgroup cd_cmd_status         CD-ROM Command Status responses

    These are the raw values the status syscall returns.
    @{
*/
#define FAILED      -1  /**< \brief Command failed */
#define NO_ACTIVE   0   /**< \brief System inactive? */
#define PROCESSING  1   /**< \brief Processing command */
#define COMPLETED   2   /**< \brief Command completed successfully */
#define ABORTED     3   /**< \brief Command aborted before completion */
/** @} */

/** \defgroup cdda_read_modes       CDDA read modes

    Valid values to pass to the cdrom_cdda_play() function for the mode
    parameter.
    @{
*/
#define CDDA_TRACKS     1   /**< \brief Play by track number */
#define CDDA_SECTORS    2   /**< \brief Play by sector number */
/** @} */

/** \defgroup cd_status_values      CD-ROM status values

    These are the values that can be returned as the status parameter from the
    cdrom_get_status() function.
    @{
*/
#define CD_STATUS_BUSY      0   /**< \brief Drive is busy */
#define CD_STATUS_PAUSED    1   /**< \brief Disc is paused */
#define CD_STATUS_STANDBY   2   /**< \brief Drive is in standby */
#define CD_STATUS_PLAYING   3   /**< \brief Drive is currently playing */
#define CD_STATUS_SEEKING   4   /**< \brief Drive is currently seeking */
#define CD_STATUS_SCANNING  5   /**< \brief Drive is scanning */
#define CD_STATUS_OPEN      6   /**< \brief Disc tray is open */
#define CD_STATUS_NO_DISC   7   /**< \brief No disc inserted */
/** @} */

/** \defgroup cd_disc_types         CD-ROM drive disc types

    These are the values that can be returned as the disc_type parameter from
    the cdrom_get_status() function.
    @{
*/
#define CD_CDDA     0       /**< \brief Audio CD (Red book) */
#define CD_CDROM    0x10    /**< \brief CD-ROM or CD-R (Yellow book) */
#define CD_CDROM_XA 0x20    /**< \brief CD-ROM XA (Yellow book extension) */
#define CD_CDI      0x30    /**< \brief CD-i (Green book) */
#define CD_GDROM    0x80    /**< \brief GD-ROM */
/** @} */


/** \defgroup sub_channel_formats         Sub channel formats
    @{
*/
#define CD_SUB_Q_CHANNEL        0
#define CD_SUB_CURRENT_POSITION 1
#define CD_SUB_MEDIA_CATALOG    2
#define CD_SUB_TRACK_ISRC       3
/** @} */

/** \brief  TOC structure returned by the BIOS.

    This is the structure that the CMD_GETTOC2 syscall command will return for
    the TOC. Note the data is in FAD, not LBA/LSN.

    \headerfile dc/cdrom.h
*/
typedef struct {
    uint32  entry[99];          /**< \brief TOC space for 99 tracks */
    uint32  first;              /**< \brief Point A0 information (1st track) */
    uint32  last;               /**< \brief Point A1 information (last track) */
    uint32  leadout_sector;     /**< \brief Point A2 information (leadout) */
} CDROM_TOC;


// for lua
uint32 TOC_LBA_(uint32 n);
uint32 TOC_ADR_(uint32 n);
uint32 TOC_CTRL_(uint32 n);
uint32 TOC_TRACK_(uint32 n);
CDROM_TOC *CDROM_TOC_new();
void CDROM_TOC_delete(CDROM_TOC *toc);

/** \brief  Set the sector size for read sectors.

    This function sets the sector size that the cdrom_read_sectors() function
    will return. Be sure to set this to the correct value for the type of
    sectors you're trying to read. Common values are 2048 (for reading CD-ROM
    sectors) or 2352 (for reading raw sectors).

    \param  size            The size of the sector data.
*/
void cdrom_set_sector_size(int size);

/** \brief  Execute a CD-ROM command.

    This function executes the specified command using the BIOS syscall for
    executing GD-ROM commands.

    \param  cmd             The command number to execute.
    \param  param           Data to pass to the syscall.

    \return                 \ref cd_cmd_response
*/
int cdrom_exec_cmd(int cmd, void *param);

/** \brief  Get the status of the GD-ROM drive.

    \param  status          Space to return the drive's status.
    \param  disc_type       Space to return the type of disc in the drive.

    \return                 \ref cd_cmd_response
    \see    cd_status_values
    \see    cd_disc_types
*/
int cdrom_get_status(int *status, int *disc_type);

/** \brief  Re-initialize the GD-ROM drive.

    This function is for reinitializing the GD-ROM drive after a disc change,
    or something of the like.

    \return                 \ref cd_cmd_response
*/
int cdrom_reinit(int p1, int cdxa, int sector_size);

/** \brief  Read the table of contents from the disc.

    This function reads the TOC from the specified session of the disc.

    \param  toc_buffer      Space to store the returned TOC in.
    \param  session         The session of the disc to read.
    \return                 \ref cd_cmd_response
*/
int cdrom_read_toc(CDROM_TOC *toc_buffer, int session);

/** \brief  Read one or more sector from a CD-ROM.

    This function reads the specified number of sectors from the disc, starting
    where requested. This will respect the size of the sectors set with
    cdrom_set_sector_size(). The buffer must have enough space to store the
    specified number of sectors.

    \param  buffer          Space to store the read sectors.
    \param  sector          The sector to start reading from.
    \param  cnt             The number of sectors to read.
    \return                 \ref cd_cmd_response
*/
int cdrom_read_sectors(int cmd, void *buffer, int sector, int cnt);

/** \brief  Locate the sector of the data track.

    This function will search the toc for the last entry that has a CTRL value
    of 4, and return its FAD address.

    \param  toc             The TOC to search through.
    \return                 The FAD of the track, or 0 if none is found.
*/

/* Get subchannel data from last read sector */
int cdrom_get_subchannel(int format, void *buffer, int buflen);

/* Set data type of cdrom sector reads */
int cdrom_set_datatype(int p1, int cdxa, int sector_size);


uint32 cdrom_locate_data_track(CDROM_TOC *toc);

/** \brief  Play CDDA audio tracks or sectors.

    This function starts playback of CDDA audio.

    \param  start           The track or sector to start playback from.
    \param  end             The track or sector to end playback at.
    \param  loops           The number of times to repeat (max of 15).
    \param  mode            The mode to play (see \ref cdda_read_modes).
    \return                 \ref cd_cmd_response
*/
int cdrom_cdda_play(uint32 start, uint32 end, uint32 loops, int mode);

/** \brief  Pause CDDA audio playback.

    \return                 \ref cd_cmd_response
*/
int cdrom_cdda_pause();

/** \brief  Resume CDDA audio playback after a pause.

    \return                 \ref cd_cmd_response
*/
int cdrom_cdda_resume();

/** \brief  Spin down the CD.

    This stops the disc in the drive from spinning until it is accessed again.

    \return                 \ref cd_cmd_response
*/
int cdrom_spin_down();

/** \brief  Initialize the GD-ROM for reading CDs.

    This initializes the CD-ROM reading system, reactivating the drive and
    handling initial setup of the disc.

    \retval 0               On success.
    \retval -1              If cdrom_init() has already been called.
*/
int cdrom_init(int p1, int cdxa, int sector_size);

/** \brief  Shutdown the CD reading system. */
void cdrom_shutdown();




/* The maximum number of streams which can be allocated at once */
#define SND_STREAM_MAX 4

/* The maximum buffer size for a stream */
#define SND_STREAM_BUFFER_MAX 0x10000

/* A stream handle */
typedef int snd_stream_hnd_t;

/* An invalid stream handle */
#define SND_STREAM_INVALID -1

/* Set "get data" callback */
//typedef void* (*snd_stream_callback_t)(snd_stream_hnd_t hnd, int smp_req, int * smp_recv);
void snd_stream_set_callback(snd_stream_hnd_t hnd, snd_stream_callback_t cb);

/* Add an effect filter to the sound stream chain. When the stream
   buffer filler needs more data, it starts out by calling the initial
   callback (set above). It then calls each function in the effect
   filter chain, which can modify the buffer and the amount of data
   available as well. Filters persist across multiple calls to _init()
   but will be emptied by _shutdown(). */
//typedef void (*snd_stream_filter_t)(snd_stream_hnd_t hnd, void * obj, int hz, int channels, void **buffer, int *samplecnt);
void snd_stream_filter_add(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc, void * obj);

/* Remove a filter added with the above function */
void snd_stream_filter_remove(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc, void * obj);

/* Prefill buffers -- do this before calling start() */
void snd_stream_prefill(snd_stream_hnd_t hnd);

/* Initialize stream system */
int snd_stream_init();

/* Shut everything down and free mem */
void snd_stream_shutdown();

/* Allocate and init a stream channel */
snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize);

/* Re-init a stream channel */
int snd_stream_reinit(snd_stream_hnd_t hnd, snd_stream_callback_t cb);

/* Destroy a stream channel */
void snd_stream_destroy(snd_stream_hnd_t hnd);

/* Enable / disable stream queueing */ 
void snd_stream_queue_enable(snd_stream_hnd_t hnd);
void snd_stream_queue_disable(snd_stream_hnd_t hnd);

/* Actually make it go (in queued mode) */
void snd_stream_queue_go(snd_stream_hnd_t hnd);

/* Start streaming */
void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st);

/* Stop streaming */
void snd_stream_stop(snd_stream_hnd_t hnd);

/* Poll streamer to load more data if neccessary */
int snd_stream_poll(snd_stream_hnd_t hnd);

/* Set the volume on the streaming channels */
void snd_stream_volume(snd_stream_hnd_t hnd, int vol);





/* Allocate a chunk of SPU RAM; we will return an offset into SPU RAM. */
uint32 snd_mem_malloc(size_t size);

/* Free a previously allocated chunk of memory */
void snd_mem_free(uint32 addr);

/* Return the number of bytes available in the largest free chunk */
uint32 snd_mem_available();

/* Reinitialize the pool with the given RAM base offset */
//int snd_mem_init(uint32 reserve);

/* Shut down the SPU allocator */
//void snd_mem_shutdown();

/* Initialize driver; note that this replaces the AICA program so that
   if you had anything else going on, it's gone now! */
//int snd_init();

/* Shut everything down and free mem */
//void snd_shutdown();

/* Queue up a request to the SH4->AICA queue; size is in uint32's */
int snd_sh4_to_aica(void *packet, uint32 size);

/* Start processing requests in the queue */
void snd_sh4_to_aica_start();

/* Stop processing requests in the queue */
void snd_sh4_to_aica_stop();

/* Transfer one packet of data from the AICA->SH4 queue. Expects to
   find AICA_CMD_MAX_SIZE dwords of space available. Returns -1
   if failure, 0 for no packets available, 1 otherwise. Failure
   might mean a permanent failure since the queue is probably out of sync. */
int snd_aica_to_sh4(void *packetout);

/* Poll for responses from the AICA. We assume here that we're not
   running in an interrupt handler (thread perhaps, of whoever
   is using us). */
void snd_poll_resp();




/* Sound effect handle type */
typedef uint32 sfxhnd_t;
#define SFXHND_INVALID 0

/* Load a sound effect from a WAV file and return a handle to it */
sfxhnd_t snd_sfx_load(const char *fn);

/* Unload a single sample */
void snd_sfx_unload(sfxhnd_t idx);

/* Unload all loaded samples and free their SPU RAM */
void snd_sfx_unload_all();

/* Play a sound effect with the given volume and panning; if the sound
   effect is in stereo, the panning is ignored. Returns the used channel
   ID (or the left channel, if stereo). */
int snd_sfx_play(sfxhnd_t idx, int vol, int pan);

/* Works like snd_sfx_play, but selects a specific channel. If the sample
   is stereo, the next channel will also be used. */
//int snd_sfx_play_chn(int chn, sfxhnd_t idx, int vol, int pan);

/* Stops a single sound effect from playing. */
//void snd_sfx_stop(int chn);

/* Stop all playing sound effects. Doesn't stop channels 0 or 1, which
   are assumed to be for streaming. */
void snd_sfx_stop_all();

/* Allocate a channel for non-sfx usage (e.g. streams). Returns -1
   on failure. */
//int snd_sfx_chn_alloc();

/* Free a channel for non-sfx usage. */
//void snd_sfx_chn_free(int chn);





/* Waits for the sound FIFO to empty */
//void spu_write_wait();

/* memcpy and memset designed for sound RAM; for addresses, don't
   bother to include the 0xa0800000 offset that is implied. 'length'
   must be a multiple of 4, but if it is not it will be rounded up. */
void spu_memload(uint32 to, void *from, int length);
void spu_memread(void *to, uint32 from, int length);
void spu_memset(uint32 to, uint32 what, int length);

/* DMA copy from SH-4 RAM to SPU RAM; length must be a multiple of 32,
   and the source and destination addresses must be aligned on 32-byte
   boundaries. If block is non-zero, this function won't return until
   the transfer is complete. If callback is non-NULL, it will be called
   upon completion (in an interrupt context!). Returns <0 on error. */
typedef g2_dma_callback_t spu_dma_callback_t;
int spu_dma_transfer(void * from, uint32 dest, uint32 length, int block,
	spu_dma_callback_t callback, ptr_t cbdata);

/* Enable/disable the SPU; note that disable implies reset of the
   ARM CPU core. */
void spu_enable();
void spu_disable();

/* Set CDDA volume: values are 0-15 */
void spu_cdda_volume(int left_volume, int right_volume);

/* Set CDDA panning: values are 0-31, 16=center */
void spu_cdda_pan(int left_pan, int right_pan);

/* Set master volume (0..15) and mono/stereo settings */
void spu_master_mixer(int volume, int stereo);

/* Initialize the SPU; by default it will be left in a state of
   reset until you upload a program. */
//int spu_init();

/* Shutdown SPU */
//int spu_shutdown();

/* These two are seperate because they have to be done at a different time */
//int spu_dma_init();
//void spu_dma_shutdown();






#define QACR0 (*(volatile unsigned int *)(void *)0xff000038)
#define QACR1 (*(volatile unsigned int *)(void *)0xff00003c)

/* clears n bytes at dest, dest must be 32-byte aligned */
void sq_clr(void *dest, int n);

/* copies n bytes from src to dest, dest must be 32-byte aligned */
void * sq_cpy(void *dest, void *src, int n);

/* fills n bytes at s with byte c, s must be 32-byte aligned */
void * sq_set(void *s, uint32 c, int n);

/* fills n bytes at s with short c, s must be 32-byte aligned */
void * sq_set16(void *s, uint32 c, int n);

/* fills n bytes at s with int c, s must be 32-byte aligned */
void * sq_set32(void *s, uint32 c, int n);






//-----------------------------------------------------------------------------
#define CT_ANY		-1 // <-- Used ONLY internally with vid_mode
#define CT_VGA		0
#define CT_RGB		2
#define CT_COMPOSITE	3

//-----------------------------------------------------------------------------
#define PM_RGB555	0
#define PM_RGB565	1
#define PM_RGB888	3

//-----------------------------------------------------------------------------
// These are more generic modes

enum {
	DM_GENERIC_FIRST = 0x1000,
	DM_320x240 = 0x1000,
	DM_640x480,
	DM_800x608,
	DM_256x256,
	DM_768x480,
	DM_768x576,
	DM_GENERIC_LAST = DM_768x576
};

//-----------------------------------------------------------------------------
// More specific modes (and actual indeces into the mode table)

enum {
	DM_INVALID = 0,
	// Valid modes below
	DM_320x240_VGA = 1,
	DM_320x240_NTSC,
	DM_640x480_VGA,
	DM_640x480_NTSC_IL,
	DM_800x608_VGA,
	DM_640x480_PAL_IL,
	DM_256x256_PAL_IL,
	DM_768x480_NTSC_IL,
	DM_768x576_PAL_IL,
	DM_768x480_PAL_IL,
	DM_320x240_PAL,
	// The below is only for counting..
	DM_SENTINEL,
	DM_MODE_COUNT
};


//-----------------------------------------------------------------------------
int vid_check_cable();

void vid_set_start(uint32 base);
void vid_flip(int fb);
void vid_border_color(int r, int g, int b);
void vid_clear(int r, int g, int b);
void vid_empty();
void vid_waitvbl();
void vid_set_mode(int dm, int pm);

void vid_init(int disp_mode, int pixel_mode);
//void vid_shutdown();

//-----------------------------------------------------------------------------

int vid_screen_shot(const char * destfn);




/**
  \file Implements wrappers for the BIOS flashrom syscalls, and some
  utilities to make it easier to use the flashrom info. Note that
  because the flash writing can be such a dangerous thing potentially
  (I haven't deleted my flash to see what happens, but given the
  info stored here it sounds like a Bad Idea(tm)) the syscalls for
  the WRITE and DELETE operations are not enabled by default. If you
  are 100% sure you really want to be writing to the flash and you
  know what you're doing, then you can edit flashrom.c and re-enable
  them there. */

/**
  An enumeration of partitions available in the flashrom. */
#define FLASHROM_PT_SYSTEM		0	/*< Factory settings (read-only, 8K) */
#define FLASHROM_PT_RESERVED	1	/*< reserved (all 0s, 8K) */
#define FLASHROM_PT_BLOCK_1		2	/*< Block allocated (16K) */
#define FLASHROM_PT_SETTINGS	3	/*< Game settings (block allocated, 32K) */
#define FLASHROM_PT_BLOCK_2		4	/*< Block allocated (64K) */

/**
  An enumeration of logical blocks available in the flashrom. */
#define FLASHROM_B1_SYSCFG			0x05	/*< System config (BLOCK_1) */
#define FLASHROM_B1_PW_SETTINGS_1	0x80	/*< PlanetWeb settings (BLOCK_1) */
#define FLASHROM_B1_PW_SETTINGS_2	0x81	/*< PlanetWeb settings (BLOCK_1) */
#define FLASHROM_B1_PW_SETTINGS_3	0x82	/*< PlanetWeb settings (BLOCK_1) */
#define FLASHROM_B1_PW_SETTINGS_4	0x83	/*< PlanetWeb settings (BLOCK_1) */
#define FLASHROM_B1_PW_SETTINGS_5	0x84	/*< PlanetWeb settings (BLOCK_1) */
#define FLASHROM_B1_PW_PPP1			0xC0	/*< PlanetWeb PPP settings (BLOCK_1) */
#define FLASHROM_B1_PW_PPP2			0xC1	/*< PlanetWeb PPP settings (BLOCK_1) */
#define FLASHROM_B1_PW_DNS			0xC2	/*< PlanetWeb DNS settings (BLOCK_1) */
#define FLASHROM_B1_PW_EMAIL1		0xC3	/*< PlanetWeb Email settings (BLOCK_1) */
#define FLASHROM_B1_PW_EMAIL2		0xC4	/*< PlanetWeb Email settings (BLOCK_1) */
#define FLASHROM_B1_PW_EMAIL_PROXY	0xC5	/*< PlanetWeb Email/Proxy settings (BLOCK_1) */
#define FLASHROM_B1_IP_SETTINGS		0xE0	/*< IP settings for BBA (BLOCK_1) */
#define FLASHROM_B1_EMAIL			0xE2	/*< Email address (BLOCK_1) */
#define FLASHROM_B1_SMTP			0xE4	/*< SMTP server setting (BLOCK_1) */
#define FLASHROM_B1_POP3			0xE5	/*< POP3 server setting (BLOCK_1) */
#define FLASHROM_B1_POP3LOGIN		0xE6	/*< POP3 login setting (BLOCK_1) */
#define FLASHROM_B1_POP3PASSWD		0xE7	/*< POP3 password setting + proxy (BLOCK_1) */
#define FLASHROM_B1_PPPLOGIN		0xE8	/*< PPP username + proxy (BLOCK_1) */
#define FLASHROM_B1_PPPPASSWD		0xE9	/*< PPP passwd (BLOCK_1) */

/**
  Implements the FLASHROM_INFO syscall; given a partition ID,
  return two ints specifying the beginning and the size of
  the partition (respectively) inside the flashrom. Returns zero
  if successful, -1 otherwise. */
int flashrom_info(int part, int * start_out, int * size_out);

/**
  Implements the FLASHROM_READ syscall; given a flashrom offset,
  an output buffer, and a count, this reads data from the
  flashrom. Returns the number of bytes read if successful,
  or -1 otherwise. */
int flashrom_read(int offset, void * buffer_out, int bytes);

/**
  Implements the FLASHROM_WRITE syscall; given a flashrom offset,
  an input buffer, and a count, this writes data to the flashrom.
  Returns the number of bytes written if successful, -1 otherwise.

  NOTE: It is not possible to write ones to the flashrom over zeros.
  If you want to do this, you must save the old data in the flashrom,
  delete it out, and save the new data back. */
int flashrom_write(int offset, void * buffer, int bytes);

/**
  Implements the FLASHROM_DELETE syscall; given a partition offset,
  that entire partition of the flashrom will be deleted and all data
  will be reset to FFs. Returns zero if successful, -1 on failure. */
int flashrom_delete(int offset);


/* Medium-level functions */
/**
  Returns a numbered logical block from the requested partition. The newest
  data is returned. 'buffer_out' must have enough room for 60 bytes of
  data. */
//int flashrom_get_block(int partid, int blockid, uint8 * buffer_out);


/* Higher level functions */

/**
  Language settings possible in the BIOS menu. These will be returned
  from flashrom_get_language(). */
#define FLASHROM_LANG_JAPANESE	0
#define FLASHROM_LANG_ENGLISH	1
#define FLASHROM_LANG_GERMAN	2
#define FLASHROM_LANG_FRENCH	3
#define FLASHROM_LANG_SPANISH	4
#define FLASHROM_LANG_ITALIAN	5

/**
  This struct will be filled by calling the flashrom_get_syscfg call
  below. */
typedef struct flashrom_syscfg {
	int	language;	/*< Language setting (see defines above) */
	int	audio;		/*< 0 == mono, 1 == stereo */
	int	autostart;	/*< 0 == off, 1 == on */
} flashrom_syscfg_t;

/**
  Retrieves the current syscfg settings and fills them into the struct
  passed in to us. */
int flashrom_get_syscfg(flashrom_syscfg_t * out);


/**
  Region settings possible in the system flash (partition 0). */
#define FLASHROM_REGION_UNKNOWN	0
#define FLASHROM_REGION_JAPAN	1
#define FLASHROM_REGION_US	2
#define FLASHROM_REGION_EUROPE	3

/**
  Retrieves the console's region code. This is still somewhat 
  experimental, it may not function 100% on all DCs. Returns
  one of the codes above or -1 on error. */
int flashrom_get_region();