/* Hardware ports. Copyright (C) 1998-2013 Free Software Foundation, Inc. Contributed by Andrew Cagney and Cygnus Solutions. This file is part of GDB, the GNU debugger. 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 . */ #include "hw-main.h" #include "hw-base.h" #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #else #ifdef HAVE_STRINGS_H #include #endif #endif #include struct hw_port_edge { int my_port; struct hw *dest; int dest_port; struct hw_port_edge *next; object_disposition disposition; }; struct hw_port_data { hw_port_event_method *to_port_event; const struct hw_port_descriptor *ports; struct hw_port_edge *edges; }; const struct hw_port_descriptor empty_hw_ports[] = { { NULL, 0, 0, 0 }, }; static void panic_hw_port_event (struct hw *me, int my_port, struct hw *source, int source_port, int level) { hw_abort (me, "no port method"); } void create_hw_port_data (struct hw *me) { me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data); set_hw_port_event (me, panic_hw_port_event); set_hw_ports (me, empty_hw_ports); } void delete_hw_port_data (struct hw *me) { hw_free (me, me->ports_of_hw); me->ports_of_hw = NULL; } void set_hw_ports (struct hw *me, const struct hw_port_descriptor ports[]) { me->ports_of_hw->ports = ports; } void set_hw_port_event (struct hw *me, hw_port_event_method *port_event) { me->ports_of_hw->to_port_event = port_event; } static void attach_hw_port_edge (struct hw *me, struct hw_port_edge **list, int my_port, struct hw *dest, int dest_port, object_disposition disposition) { struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge); new_edge->my_port = my_port; new_edge->dest = dest; new_edge->dest_port = dest_port; new_edge->next = *list; new_edge->disposition = disposition; *list = new_edge; } static void detach_hw_port_edge (struct hw *me, struct hw_port_edge **list, int my_port, struct hw *dest, int dest_port) { while (*list != NULL) { struct hw_port_edge *old_edge = *list; if (old_edge->dest == dest && old_edge->dest_port == dest_port && old_edge->my_port == my_port) { if (old_edge->disposition == permenant_object) hw_abort (me, "attempt to delete permenant port edge"); *list = old_edge->next; hw_free (me, old_edge); return; } } hw_abort (me, "attempt to delete unattached port"); } #if 0 static void clean_hw_port_edges (struct hw_port_edge **list) { while (*list != NULL) { struct hw_port_edge *old_edge = *list; switch (old_edge->disposition) { case permenant_object: list = &old_edge->next; break; case temporary_object: *list = old_edge->next; hw_free (me, old_edge); break; } } } #endif /* Ports: */ void hw_port_event (struct hw *me, int my_port, int level) { int found_an_edge = 0; struct hw_port_edge *edge; /* device's lines directly connected */ for (edge = me->ports_of_hw->edges; edge != NULL; edge = edge->next) { if (edge->my_port == my_port) { edge->dest->ports_of_hw->to_port_event (edge->dest, edge->dest_port, me, my_port, level); found_an_edge = 1; } } if (!found_an_edge) hw_abort (me, "No edge for port %d", my_port); } void hw_port_attach (struct hw *me, int my_port, struct hw *dest, int dest_port, object_disposition disposition) { attach_hw_port_edge (me, &me->ports_of_hw->edges, my_port, dest, dest_port, disposition); } void hw_port_detach (struct hw *me, int my_port, struct hw *dest, int dest_port) { detach_hw_port_edge (me, &me->ports_of_hw->edges, my_port, dest, dest_port); } void hw_port_traverse (struct hw *me, hw_port_traverse_function *handler, void *data) { struct hw_port_edge *port_edge; for (port_edge = me->ports_of_hw->edges; port_edge != NULL; port_edge = port_edge->next) { handler (me, port_edge->my_port, port_edge->dest, port_edge->dest_port, data); } } int hw_port_decode (struct hw *me, const char *port_name, port_direction direction) { if (port_name == NULL || port_name[0] == '\0') return 0; if (isdigit (port_name[0])) { return strtoul (port_name, NULL, 0); } else { const struct hw_port_descriptor *ports = me->ports_of_hw->ports; if (ports != NULL) { while (ports->name != NULL) { if (ports->direction == bidirect_port || ports->direction == direction) { if (ports->nr_ports > 0) { int len = strlen (ports->name); if (strncmp (port_name, ports->name, len) == 0) { if (port_name[len] == '\0') return ports->number; else if (isdigit (port_name[len])) { int port = (ports->number + strtoul (&port_name[len], NULL, 0)); if (port >= ports->number + ports->nr_ports) hw_abort (me, "Port %s out of range", port_name); return port; } } } else if (strcmp (port_name, ports->name) == 0) return ports->number; } ports++; } } } hw_abort (me, "Unrecognized port %s", port_name); return 0; } int hw_port_encode (struct hw *me, int port_number, char *buf, int sizeof_buf, port_direction direction) { const struct hw_port_descriptor *ports = NULL; ports = me->ports_of_hw->ports; if (ports != NULL) { while (ports->name != NULL) { if (ports->direction == bidirect_port || ports->direction == direction) { if (ports->nr_ports > 0) { if (port_number >= ports->number && port_number < ports->number + ports->nr_ports) { strcpy (buf, ports->name); sprintf (buf + strlen (buf), "%d", port_number - ports->number); if (strlen (buf) >= sizeof_buf) hw_abort (me, "hw_port_encode: buffer overflow"); return strlen (buf); } } else { if (ports->number == port_number) { if (strlen (ports->name) >= sizeof_buf) hw_abort (me, "hw_port_encode: buffer overflow"); strcpy (buf, ports->name); return strlen (buf); } } } ports++; } } sprintf (buf, "%d", port_number); if (strlen (buf) >= sizeof_buf) hw_abort (me, "hw_port_encode: buffer overflow"); return strlen (buf); }