summaryrefslogtreecommitdiff
path: root/gdb/rdi-share/devsw.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/rdi-share/devsw.c')
-rw-r--r--gdb/rdi-share/devsw.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/gdb/rdi-share/devsw.c b/gdb/rdi-share/devsw.c
new file mode 100644
index 00000000000..7fa142b4722
--- /dev/null
+++ b/gdb/rdi-share/devsw.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
+ *
+ * This software may be freely used, copied, modified, and distributed
+ * provided that the above copyright notice is preserved in all copies of the
+ * software.
+ */
+
+/* -*-C-*-
+ *
+ * $Revision$
+ * $Date$
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "adp.h"
+#include "hsys.h"
+#include "rxtx.h"
+#include "drivers.h"
+#include "buffers.h"
+#include "devclnt.h"
+#include "adperr.h"
+#include "devsw.h"
+#include "hostchan.h"
+#include "logging.h"
+
+/*
+ * TODO: this should be adjustable - it could be done by defining
+ * a reason code for DevSW_Ioctl. It could even be a
+ * per-devicechannel parameter.
+ */
+static const unsigned int allocsize = ADP_BUFFER_MIN_SIZE;
+
+#define illegalDevChanID(type) ((type) >= DC_NUM_CHANNELS)
+
+/**********************************************************************/
+
+/*
+ * Function: initialise_read
+ * Purpose: Set up a read request for another packet
+ *
+ * Params:
+ * In/Out: ds State structure to be initialised
+ *
+ * Returns:
+ * OK: 0
+ * Error: -1
+ */
+static int initialise_read(DevSWState *ds)
+{
+ struct data_packet *dp;
+
+ /*
+ * try to claim the structure that will
+ * eventually hold the new packet.
+ */
+ if ((ds->ds_nextreadpacket = DevSW_AllocatePacket(allocsize)) == NULL)
+ return -1;
+
+ /*
+ * Calls into the device driver use the DriverCall structure: use
+ * the buffer we have just allocated, and declare its size. We
+ * are also obliged to clear the driver's context pointer.
+ */
+ dp = &ds->ds_activeread.dc_packet;
+ dp->buf_len = allocsize;
+ dp->data = ds->ds_nextreadpacket->pk_buffer;
+
+ ds->ds_activeread.dc_context = NULL;
+
+ return 0;
+}
+
+/*
+ * Function: initialise_write
+ * Purpose: Set up a write request for another packet
+ *
+ * Params:
+ * Input: packet The packet to be written
+ *
+ * type The type of the packet
+ *
+ * In/Out: dc The structure to be intialised
+ *
+ * Returns: Nothing
+ */
+static void initialise_write(DriverCall *dc, Packet *packet, DevChanID type)
+{
+ struct data_packet *dp = &dc->dc_packet;
+
+ dp->len = packet->pk_length;
+ dp->data = packet->pk_buffer;
+ dp->type = type;
+
+ /*
+ * we are required to clear the state structure for the driver
+ */
+ dc->dc_context = NULL;
+}
+
+/*
+ * Function: enqueue_packet
+ * Purpose: move a newly read packet onto the appropriate queue
+ * of read packets
+ *
+ * Params:
+ * In/Out: ds State structure with new packet
+ *
+ * Returns: Nothing
+ */
+static void enqueue_packet(DevSWState *ds)
+{
+ struct data_packet *dp = &ds->ds_activeread.dc_packet;
+ Packet *packet = ds->ds_nextreadpacket;
+
+ /*
+ * transfer the length
+ */
+ packet->pk_length = dp->len;
+
+ /*
+ * take this packet out of the incoming slot
+ */
+ ds->ds_nextreadpacket = NULL;
+
+ /*
+ * try to put it on the correct input queue
+ */
+ if (illegalDevChanID(dp->type))
+ {
+ /* this shouldn't happen */
+ WARN("Illegal type for Rx packet");
+ DevSW_FreePacket(packet);
+ }
+ else
+ Adp_addToQueue(&ds->ds_readqueue[dp->type], packet);
+}
+
+/*
+ * Function: flush_packet
+ * Purpose: Send a packet to the device driver
+ *
+ * Params:
+ * Input: device The device to be written to
+ *
+ * In/Out: dc Describes the packet to be sent
+ *
+ * Returns: Nothing
+ *
+ * Post-conditions: If the whole packet was accepted by the device
+ * driver, then dc->dc_packet.data will be
+ * set to NULL.
+ */
+static void flush_packet(const DeviceDescr *device, DriverCall *dc)
+{
+ if (device->DeviceWrite(dc) > 0)
+ /*
+ * the whole packet was swallowed
+ */
+ dc->dc_packet.data = NULL;
+}
+
+/**********************************************************************/
+
+/*
+ * These are the externally visible functions. They are documented in
+ * devsw.h
+ */
+Packet *DevSW_AllocatePacket(const unsigned int length)
+{
+ Packet *pk;
+
+ if ((pk = malloc(sizeof(*pk))) == NULL)
+ {
+ WARN("malloc failure");
+ return NULL;
+ }
+
+ if ((pk->pk_buffer = malloc(length+CHAN_HEADER_SIZE)) == NULL)
+ {
+ WARN("malloc failure");
+ free(pk);
+ return NULL;
+ }
+
+ return pk;
+}
+
+void DevSW_FreePacket(Packet *pk)
+{
+ free(pk->pk_buffer);
+ free(pk);
+}
+
+AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg,
+ const DevChanID type)
+{
+ DevSWState *ds;
+
+ /*
+ * is this the very first open call for this driver?
+ */
+ if ((ds = (DevSWState *)(device->SwitcherState)) == NULL)
+ {
+ /*
+ * yes, it is: initialise state
+ */
+ if ((ds = malloc(sizeof(*ds))) == NULL)
+ /* give up */
+ return adp_malloc_failure;
+
+ (void)memset(ds, 0, sizeof(*ds));
+ device->SwitcherState = (void *)ds;
+ }
+
+ /*
+ * check that we haven't already been opened for this type
+ */
+ if ((ds->ds_opendevchans & (1 << type)) != 0)
+ return adp_device_already_open;
+
+ /*
+ * if no opens have been done for this device, then do it now
+ */
+ if (ds->ds_opendevchans == 0)
+ if (device->DeviceOpen(name, arg) < 0)
+ return adp_device_open_failed;
+
+ /*
+ * open has finished
+ */
+ ds->ds_opendevchans |= (1 << type);
+ return adp_ok;
+}
+
+AdpErrs DevSW_Match(const DeviceDescr *device, const char *name,
+ const char *arg)
+{
+ return (device->DeviceMatch(name, arg) == -1) ? adp_failed : adp_ok;
+}
+
+AdpErrs DevSW_Close(const DeviceDescr *device, const DevChanID type)
+{
+ DevSWState *ds = (DevSWState *)(device->SwitcherState);
+ Packet *pk;
+
+ if ((ds->ds_opendevchans & (1 << type)) == 0)
+ return adp_device_not_open;
+
+ ds->ds_opendevchans &= ~(1 << type);
+
+ /*
+ * if this is the last close for this channel, then inform the driver
+ */
+ if (ds->ds_opendevchans == 0)
+ device->DeviceClose();
+
+ /*
+ * release all packets of the appropriate type
+ */
+ for (pk = Adp_removeFromQueue(&(ds->ds_readqueue[type]));
+ pk != NULL;
+ pk = Adp_removeFromQueue(&(ds->ds_readqueue[type])))
+ DevSW_FreePacket(pk);
+
+ /* Free memory */
+ free ((char *) device->SwitcherState);
+ device->SwitcherState = 0x0;
+
+ /* that's all */
+ return adp_ok;
+}
+
+AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type,
+ Packet **packet, bool block)
+{
+ int read_err;
+ DevSWState *ds = device->SwitcherState;
+
+ /*
+ * To try to get information out of the device driver as
+ * quickly as possible, we try and read more packets, even
+ * if a completed packet is already available.
+ */
+
+ /*
+ * have we got a packet currently pending?
+ */
+ if (ds->ds_nextreadpacket == NULL)
+ /*
+ * no - set things up
+ */
+ if (initialise_read(ds) < 0) {
+ /*
+ * we failed to initialise the next packet, but can
+ * still return a packet that has already arrived.
+ */
+ *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
+ return adp_ok;
+ }
+ read_err = device->DeviceRead(&ds->ds_activeread, block);
+ switch (read_err) {
+ case 1:
+ /*
+ * driver has pulled in a complete packet, queue it up
+ */
+#ifdef RET_DEBUG
+ printf("got a complete packet\n");
+#endif
+ enqueue_packet(ds);
+ *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
+ return adp_ok;
+ case 0:
+ /*
+ * OK, return the head of the read queue for the given type
+ */
+ /* enqueue_packet(ds); */
+ *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
+ return adp_ok;
+ case -1:
+#ifdef RET_DEBUG
+ printf("got a bad packet\n");
+#endif
+ /* bad packet */
+ *packet = NULL;
+ return adp_bad_packet;
+ default:
+ panic("DevSW_Read: bad read status %d", read_err);
+ }
+ return 0; /* get rid of a potential compiler warning */
+}
+
+
+AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device)
+{
+ struct DriverCall *dc;
+ struct data_packet *dp;
+
+ dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
+ dp = &dc->dc_packet;
+
+ /*
+ * try to flush any packet that is still being written
+ */
+ if (dp->data != NULL)
+ {
+ flush_packet(device, dc);
+
+ /* see if it has gone */
+ if (dp->data != NULL)
+ return adp_write_busy;
+ else
+ return adp_ok;
+ }
+ else
+ return adp_ok;
+}
+
+
+AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type)
+{
+ struct DriverCall *dc;
+ struct data_packet *dp;
+
+ dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
+ dp = &dc->dc_packet;
+
+ if (illegalDevChanID(type))
+ return adp_illegal_args;
+
+ /*
+ * try to flush any packet that is still being written
+ */
+ if (DevSW_FlushPendingWrite(device) != adp_ok)
+ return adp_write_busy;
+
+ /*
+ * we can take this packet - set things up, then try to get rid of it
+ */
+ initialise_write(dc, packet, type);
+ flush_packet(device, dc);
+
+ return adp_ok;
+}
+
+AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args)
+{
+ return (device->DeviceIoctl(opcode, args) < 0) ? adp_failed : adp_ok;
+}
+
+bool DevSW_WriteFinished(const DeviceDescr *device)
+{
+ struct DriverCall *dc;
+ struct data_packet *dp;
+
+ dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
+ dp = &dc->dc_packet;
+
+ return (dp == NULL || dp->data == NULL);
+}
+
+/* EOF devsw.c */