/***************************************************************************

    devcb.h

    Device callback interface helpers.

    Copyright Nicola Salmoria and the MAME Team.
    Visit http://mamedev.org for licensing and usage restrictions.

****************************************************************************

    These functions are used to adapt multiple read/write handler types
    to be used with device I/O. In general, a device is expected to
    declare its desired callback type, and these functions allow other
    callback types to be adapted appropriately.

    The desired callback types currently supported include:

        read_line_device_func:  (device)
        write_line_device_func: (device, data)
        read8_device_func:      (device, offset)
        write8_device_func:     (device, offset, data)

    The adapted callback types supported are:

        input port              (port)
        cpu input line          (cpu input line)
        read_line_device_func:  (device)
        write_line_device_func: (device, data)
        read8_device_func:      (device, offset)
        write8_device_func:     (device, offset, data)
        read8_space_func:       (space, offset)
        write8_space_func:      (space, offset, data)

***************************************************************************/

#pragma once

#ifndef __DEVCB_H__
#define __DEVCB_H__

#include "devintrf.h"
#include "memory.h"


/***************************************************************************
    CONSTANTS
***************************************************************************/

#define DEVCB_TYPE_NULL				(0)
#define DEVCB_TYPE_SELF				(1)
#define DEVCB_TYPE_INPUT			(2)
#define DEVCB_TYPE_DEVICE			(3)
#define DEVCB_TYPE_MEMORY(space)	(4 + (space))
#define DEVCB_TYPE_CPU_LINE(line)	(4 + ADDRESS_SPACES + (line))



/***************************************************************************
    MACROS
***************************************************************************/

#define DEVCB_NULL							{ DEVCB_TYPE_NULL }

/* standard line or read/write handlers with the calling device passed */
#define DEVCB_LINE(func)					{ DEVCB_TYPE_SELF, NULL, (func), NULL, NULL }
#define DEVCB_LINE_GND						{ DEVCB_TYPE_SELF, NULL, devcb_line_gnd_r, NULL, NULL }
#define DEVCB_LINE_VCC						{ DEVCB_TYPE_SELF, NULL, devcb_line_vcc_r, NULL, NULL }
#define DEVCB_HANDLER(func)					{ DEVCB_TYPE_SELF, NULL, NULL, (func), NULL }

/* line or read/write handlers for another device */
#define DEVCB_DEVICE_LINE(tag,func)			{ DEVCB_TYPE_DEVICE, tag, (func), NULL, NULL }
#define DEVCB_DEVICE_HANDLER(tag,func)		{ DEVCB_TYPE_DEVICE, tag, NULL, (func), NULL }

/* read/write handlers for a given CPU's address space */
#define DEVCB_MEMORY_HANDLER(cpu,space,func) { DEVCB_TYPE_MEMORY(ADDRESS_SPACE_##space), (cpu), NULL, NULL, (func) }

/* read handlers for an I/O port by tag */
#define DEVCB_INPUT_PORT(tag)				{ DEVCB_TYPE_INPUT, (tag), NULL, NULL, NULL }

/* write handlers for a CPU input line */
#define DEVCB_CPU_INPUT_LINE(tag,line)		{ DEVCB_TYPE_CPU_LINE(line), (tag), NULL, NULL, NULL }


/* macros for defining read_line/write_line functions */
#define READ_LINE_DEVICE_HANDLER(name) 		int  name(ATTR_UNUSED const device_config *device)
#define WRITE_LINE_DEVICE_HANDLER(name) 	void name(ATTR_UNUSED const device_config *device, ATTR_UNUSED int state)



/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* read/write types for I/O lines (similar to read/write handlers but no offset) */
typedef int (*read_line_device_func)(const device_config *device);
typedef void (*write_line_device_func)(const device_config *device, int state);


/* static structure used for device configuration when the desired callback type is a read_line_device_func */
typedef struct _devcb_read_line devcb_read_line;
struct _devcb_read_line
{
	UINT32					type;			/* one of the special DEVCB_TYPE values */
	const char *			tag;			/* tag of target, where appropriate */
	read_line_device_func	readline;		/* read line function */
	read8_device_func		readdevice;		/* read device function */
	read8_space_func		readspace;		/* read space function */
};

typedef struct _devcb_resolved_read_line devcb_resolved_read_line;
struct _devcb_resolved_read_line
{
	const void *			target;			/* target object */
	read_line_device_func	read;			/* read line function */
	const void *			realtarget;		/* real target object for stubs */
	union
	{
		read8_device_func	readdevice;
		read8_space_func	readspace;
	} real;									/* real read function for stubs */
};


/* static structure used for device configuration when the desired callback type is a write_line_device_func */
typedef struct _devcb_write_line devcb_write_line;
struct _devcb_write_line
{
	UINT32					type;			/* one of the special DEVCB_TYPE values */
	const char *			tag;			/* tag of target, where appropriate */
	write_line_device_func	writeline;		/* write line function */
	write8_device_func		writedevice;	/* write device function */
	write8_space_func		writespace;		/* write space function */
};

typedef struct _devcb_resolved_write_line devcb_resolved_write_line;
struct _devcb_resolved_write_line
{
	const void *			target;			/* target object */
	write_line_device_func	write;			/* write line function */
	const void *			realtarget;		/* real target object for stubs */
	union
	{
		write8_device_func	writedevice;
		write8_space_func	writespace;
		int					writeline;
	} real;									/* real write function for stubs */
};


/* static structure used for device configuration when the desired callback type is a read8_device_func */
typedef struct _devcb_read8 devcb_read8;
struct _devcb_read8
{
	UINT32					type;			/* one of the special DEVCB_TYPE values */
	const char *			tag;			/* tag of target, where appropriate */
	read_line_device_func	readline;		/* read line function */
	read8_device_func		readdevice;		/* read device function */
	read8_space_func		readspace;		/* read space function */
};

typedef struct _devcb_resolved_read8 devcb_resolved_read8;
struct _devcb_resolved_read8
{
	const void *			target;			/* target object */
	read8_device_func		read;			/* read function */
	const void *			realtarget;		/* real target object for stubs */
	union
	{
		read8_device_func	readdevice;
		read8_space_func	readspace;
		read_line_device_func readline;
	} real;									/* real read function for stubs */
};


/* static structure used for device configuration when the desired callback type is a write8_device_func */
typedef struct _devcb_write8 devcb_write8;
struct _devcb_write8
{
	UINT32					type;			/* one of the special DEVCB_TYPE values */
	const char *			tag;			/* tag of target, where appropriate */
	write_line_device_func	writeline;		/* write line function */
	write8_device_func		writedevice;	/* write device function */
	write8_space_func		writespace;		/* write space function */
};

typedef struct _devcb_resolved_write8 devcb_resolved_write8;
struct _devcb_resolved_write8
{
	const void *			target;			/* target object */
	write8_device_func		write;			/* write function */
	const void *			realtarget;		/* real target object for stubs */
	union
	{
		write8_device_func	writedevice;
		write8_space_func	writespace;
		write_line_device_func writeline;
	} real;									/* real write function for stubs */
};



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/


/* ----- static-to-live conversion ----- */

/* convert a static read line definition to a live definition */
void devcb_resolve_read_line(devcb_resolved_read_line *resolved, const devcb_read_line *config, const device_config *device);

/* convert a static write line definition to a live definition */
void devcb_resolve_write_line(devcb_resolved_write_line *resolved, const devcb_write_line *config, const device_config *device);

/* convert a static 8-bit read definition to a live definition */
void devcb_resolve_read8(devcb_resolved_read8 *resolved, const devcb_read8 *config, const device_config *device);

/* convert a static 8-bit write definition to a live definition */
void devcb_resolve_write8(devcb_resolved_write8 *resolved, const devcb_write8 *config, const device_config *device);



/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

/*-------------------------------------------------
    devcb_call_read_line - call through a
    resolved read_line handler
-------------------------------------------------*/

INLINE int devcb_call_read_line(const devcb_resolved_read_line *resolved)
{
	return (resolved->read != NULL) ? (*resolved->read)((const device_config *)resolved->target) : 0;
}


/*-------------------------------------------------
    devcb_call_read8 - call through a
    resolved read8 handler
-------------------------------------------------*/

INLINE int devcb_call_read8(const devcb_resolved_read8 *resolved, offs_t offset)
{
	return (resolved->read != NULL) ? (*resolved->read)((const device_config *)resolved->target, offset) : 0;
}


/*-------------------------------------------------
    devcb_call_write_line - call through a
    resolved write_line handler
-------------------------------------------------*/

INLINE void devcb_call_write_line(const devcb_resolved_write_line *resolved, int state)
{
	if (resolved->write != NULL)
		(*resolved->write)((const device_config *)resolved->target, state);
}


/*-------------------------------------------------
    devcb_call_write8 - call through a
    resolved write8 handler
-------------------------------------------------*/

INLINE void devcb_call_write8(const devcb_resolved_write8 *resolved, offs_t offset, UINT8 data)
{
	if (resolved->write != NULL)
		(*resolved->write)((const device_config *)resolved->target, offset, data);
}

/*-------------------------------------------------
    devcb_line_gnd_r - input tied to GND
-------------------------------------------------*/

INLINE READ_LINE_DEVICE_HANDLER( devcb_line_gnd_r )
{
	return 0;
}

/*-------------------------------------------------
    devcb_line_vcc_r - input tied to Vcc
-------------------------------------------------*/

INLINE READ_LINE_DEVICE_HANDLER( devcb_line_vcc_r )
{
	return 1;
}

#endif	/* __DEVCB_H__ */
