/*  This file is part of the program psim.

    Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 
    */


#ifndef _DEVICE_TABLE_H_
#define _DEVICE_TABLE_H_

#include "basics.h"
#include "device.h"
#include "tree.h"

#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif


typedef struct _device_callbacks device_callbacks;


/* The creator, returns a pointer to any data that should be allocated
   once during (multiple) simulation runs */

typedef void *(device_creator)
     (const char *name,
      const device_unit *unit_address,
      const char *args);


/* two stages of initialization */

typedef void (device_init_callback)
     (device *me);
     
typedef struct _device_init_callbacks {
  device_init_callback *address; /* NULL - ignore */
  device_init_callback *data; /* NULL - ignore */
} device_init_callbacks;


/* attaching/detaching a devices address space to its parent */

typedef void (device_address_callback)
     (device *me,
      attach_type attach,
      int space,
      unsigned_word addr,
      unsigned nr_bytes,
      access_type access,
      device *client); /*callback/default*/

typedef struct _device_address_callbacks {
  device_address_callback *attach;
  device_address_callback *detach;
} device_address_callbacks;


/* I/O operations - from parent */

typedef unsigned (device_io_read_buffer_callback)
     (device *me,
      void *dest,
      int space,
      unsigned_word addr,
      unsigned nr_bytes,
      cpu *processor,
      unsigned_word cia);

typedef unsigned (device_io_write_buffer_callback)
     (device *me,
      const void *source,
      int space,
      unsigned_word addr,
      unsigned nr_bytes,
      cpu *processor,
      unsigned_word cia);

typedef struct _device_io_callbacks { /* NULL - error */
  device_io_read_buffer_callback *read_buffer;
  device_io_write_buffer_callback *write_buffer;
} device_io_callbacks;


/* DMA transfers by a device via its parent */

typedef unsigned (device_dma_read_buffer_callback)
     (device *me,
      void *dest,
      int space,
      unsigned_word addr,
      unsigned nr_bytes);

typedef unsigned (device_dma_write_buffer_callback)
     (device *me,
      const void *source,
      int space,
      unsigned_word addr,
      unsigned nr_bytes,
      int violate_read_only_section);

typedef struct _device_dma_callbacks { /* NULL - error */
  device_dma_read_buffer_callback *read_buffer;
  device_dma_write_buffer_callback *write_buffer;
} device_dma_callbacks;


/* Interrupts */

typedef void (device_interrupt_event_callback)
     (device *me,
      int my_port,
      device *source,
      int source_port,
      int level,
      cpu *processor,
      unsigned_word cia);

typedef void (device_child_interrupt_event_callback)
     (device *me,
      device *parent,
      device *source,
      int source_port,
      int level,
      cpu *processor,
      unsigned_word cia);
      
typedef struct _device_interrupt_port_descriptor {
  const char *name;
  int number; 
  int nr_ports;
  port_direction direction;
} device_interrupt_port_descriptor;

typedef struct _device_interrupt_callbacks {
  device_interrupt_event_callback *event;
  device_child_interrupt_event_callback *child_event;
  const device_interrupt_port_descriptor *ports;
} device_interrupt_callbacks;


/* symbolic value decoding */

typedef int (device_unit_decode_callback)
     (device *bus,
      const char *unit,
      device_unit *address);

typedef int (device_unit_encode_callback)
     (device *bus,
      const device_unit *unit_address,
      char *buf,
      int sizeof_buf);

typedef int (device_address_to_attach_address_callback)
     (device *bus,
      const device_unit *address,
      int *attach_space,
      unsigned_word *attach_address,
      device *client);

typedef int (device_size_to_attach_size_callback)
     (device *bus,
      const device_unit *size,
      unsigned *nr_bytes,
      device *client);

typedef struct _device_convert_callbacks {
  device_unit_decode_callback *decode_unit;
  device_unit_encode_callback *encode_unit;
  device_address_to_attach_address_callback *address_to_attach_address;
  device_size_to_attach_size_callback *size_to_attach_size;
} device_convert_callbacks;


/* instances */

typedef void (device_instance_delete_callback)
     (device_instance *instance);

typedef int (device_instance_read_callback)
     (device_instance *instance,
      void *buf,
      unsigned_word len);

typedef int (device_instance_write_callback)
     (device_instance *instance,
      const void *buf,
      unsigned_word len);

typedef int (device_instance_seek_callback)
     (device_instance *instance,
      unsigned_word pos_hi,
      unsigned_word pos_lo);

typedef int (device_instance_method)
     (device_instance *instance,
      int n_stack_args,
      unsigned_cell stack_args[/*n_stack_args*/],
      int n_stack_returns,
      unsigned_cell stack_returns[/*n_stack_returns*/]);

typedef struct _device_instance_methods {
  const char *name;
  device_instance_method *method;
} device_instance_methods;

struct _device_instance_callbacks { /* NULL - error */
  device_instance_delete_callback *delete;
  device_instance_read_callback *read;
  device_instance_write_callback *write;
  device_instance_seek_callback *seek;
  const device_instance_methods *methods;
};

typedef device_instance *(device_create_instance_callback)
     (device *me,
      const char *full_path,
      const char *args);

typedef device_instance *(package_create_instance_callback)
     (device_instance *parent,
      const char *args);


/* all else fails */

typedef int (device_ioctl_callback)
     (device *me,
      cpu *processor,
      unsigned_word cia,
      device_ioctl_request request,
      va_list ap);

typedef void (device_usage_callback)
     (int verbose);


/* the callbacks */

struct _device_callbacks {

  /* initialization */
  device_init_callbacks init;

  /* address/data config - from child */
  device_address_callbacks address;

  /* address/data transfer - from parent */
  device_io_callbacks io;

  /* address/data transfer - from child */
  device_dma_callbacks dma;

  /* interrupt signalling */
  device_interrupt_callbacks interrupt;

  /* bus address decoding */
  device_convert_callbacks convert;

  /* instances */
  device_create_instance_callback *instance_create;

  /* back door to anything we've forgot */
  device_ioctl_callback *ioctl;
  device_usage_callback *usage;
};


/* Table of all the devices and a function to lookup/create a device
   from its name */

typedef struct _device_descriptor device_descriptor;
struct _device_descriptor {
  const char *name;
  device_creator *creator;
  const device_callbacks *callbacks;
};

extern const device_descriptor *const device_table[];
#include "hw.h"


/* Pass through, ignore and generic callback functions.  A call going
   towards the root device are passed on up, local calls are ignored
   and call downs abort */

extern device_address_callback passthrough_device_address_attach;
extern device_address_callback passthrough_device_address_detach;
extern device_dma_read_buffer_callback passthrough_device_dma_read_buffer;
extern device_dma_write_buffer_callback passthrough_device_dma_write_buffer;

extern device_unit_decode_callback ignore_device_unit_decode;

extern device_init_callback generic_device_init_address;
extern device_unit_decode_callback generic_device_unit_decode;
extern device_unit_encode_callback generic_device_unit_encode;
extern device_address_to_attach_address_callback generic_device_address_to_attach_address;
extern device_size_to_attach_size_callback generic_device_size_to_attach_size;


extern const device_callbacks passthrough_device_callbacks;

#endif /* _DEVICE_TABLE_H_ */
