diff options
Diffstat (limited to 'gdb/rdi-share/devsw.c')
-rw-r--r-- | gdb/rdi-share/devsw.c | 404 |
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 */ |