1/* Hardware ports. 2 Copyright (C) 1998-2023 Free Software Foundation, Inc. 3 Contributed by Andrew Cagney and Cygnus Solutions. 4 5This file is part of GDB, the GNU debugger. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20/* This must come before any other includes. */ 21#include "defs.h" 22 23#include <ctype.h> 24#include <stdlib.h> 25#include <string.h> 26 27#include "hw-main.h" 28#include "hw-base.h" 29 30struct hw_port_edge 31{ 32 int my_port; 33 struct hw *dest; 34 int dest_port; 35 struct hw_port_edge *next; 36 object_disposition disposition; 37}; 38 39struct hw_port_data 40{ 41 hw_port_event_method *to_port_event; 42 const struct hw_port_descriptor *ports; 43 struct hw_port_edge *edges; 44}; 45 46const struct hw_port_descriptor empty_hw_ports[] = 47{ 48 { NULL, 0, 0, 0 }, 49}; 50 51static void 52panic_hw_port_event (struct hw *me, 53 int my_port, 54 struct hw *source, 55 int source_port, 56 int level) 57{ 58 hw_abort (me, "no port method"); 59} 60 61void 62create_hw_port_data (struct hw *me) 63{ 64 me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data); 65 set_hw_port_event (me, panic_hw_port_event); 66 set_hw_ports (me, empty_hw_ports); 67} 68 69void 70delete_hw_port_data (struct hw *me) 71{ 72 hw_free (me, me->ports_of_hw); 73 me->ports_of_hw = NULL; 74} 75 76void 77set_hw_ports (struct hw *me, 78 const struct hw_port_descriptor ports[]) 79{ 80 me->ports_of_hw->ports = ports; 81} 82 83void 84set_hw_port_event (struct hw *me, 85 hw_port_event_method *port_event) 86{ 87 me->ports_of_hw->to_port_event = port_event; 88} 89 90 91static void 92attach_hw_port_edge (struct hw *me, 93 struct hw_port_edge **list, 94 int my_port, 95 struct hw *dest, 96 int dest_port, 97 object_disposition disposition) 98{ 99 struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge); 100 new_edge->my_port = my_port; 101 new_edge->dest = dest; 102 new_edge->dest_port = dest_port; 103 new_edge->next = *list; 104 new_edge->disposition = disposition; 105 *list = new_edge; 106} 107 108 109static void 110detach_hw_port_edge (struct hw *me, 111 struct hw_port_edge **list, 112 int my_port, 113 struct hw *dest, 114 int dest_port) 115{ 116 while (*list != NULL) 117 { 118 struct hw_port_edge *old_edge = *list; 119 if (old_edge->dest == dest 120 && old_edge->dest_port == dest_port 121 && old_edge->my_port == my_port) 122 { 123 if (old_edge->disposition == permenant_object) 124 hw_abort (me, "attempt to delete permenant port edge"); 125 *list = old_edge->next; 126 hw_free (me, old_edge); 127 return; 128 } 129 } 130 hw_abort (me, "attempt to delete unattached port"); 131} 132 133 134#if 0 135static void 136clean_hw_port_edges (struct hw_port_edge **list) 137{ 138 while (*list != NULL) 139 { 140 struct hw_port_edge *old_edge = *list; 141 switch (old_edge->disposition) 142 { 143 case permenant_object: 144 list = &old_edge->next; 145 break; 146 case temporary_object: 147 *list = old_edge->next; 148 hw_free (me, old_edge); 149 break; 150 } 151 } 152} 153#endif 154 155 156/* Ports: */ 157 158void 159hw_port_event (struct hw *me, 160 int my_port, 161 int level) 162{ 163 int found_an_edge = 0; 164 struct hw_port_edge *edge; 165 /* device's lines directly connected */ 166 for (edge = me->ports_of_hw->edges; 167 edge != NULL; 168 edge = edge->next) 169 { 170 if (edge->my_port == my_port) 171 { 172 edge->dest->ports_of_hw->to_port_event (edge->dest, 173 edge->dest_port, 174 me, 175 my_port, 176 level); 177 found_an_edge = 1; 178 } 179 } 180 if (!found_an_edge) 181 hw_abort (me, "No edge for port %d", my_port); 182} 183 184 185void 186hw_port_attach (struct hw *me, 187 int my_port, 188 struct hw *dest, 189 int dest_port, 190 object_disposition disposition) 191{ 192 attach_hw_port_edge (me, 193 &me->ports_of_hw->edges, 194 my_port, 195 dest, 196 dest_port, 197 disposition); 198} 199 200 201void 202hw_port_detach (struct hw *me, 203 int my_port, 204 struct hw *dest, 205 int dest_port) 206{ 207 detach_hw_port_edge (me, 208 &me->ports_of_hw->edges, 209 my_port, 210 dest, 211 dest_port); 212} 213 214 215void 216hw_port_traverse (struct hw *me, 217 hw_port_traverse_function *handler, 218 void *data) 219{ 220 struct hw_port_edge *port_edge; 221 for (port_edge = me->ports_of_hw->edges; 222 port_edge != NULL; 223 port_edge = port_edge->next) 224 { 225 handler (me, port_edge->my_port, 226 port_edge->dest, port_edge->dest_port, 227 data); 228 } 229} 230 231 232int 233hw_port_decode (struct hw *me, 234 const char *port_name, 235 port_direction direction) 236{ 237 if (port_name == NULL || port_name[0] == '\0') 238 return 0; 239 if (isdigit (port_name[0])) 240 { 241 return strtoul (port_name, NULL, 0); 242 } 243 else 244 { 245 const struct hw_port_descriptor *ports = 246 me->ports_of_hw->ports; 247 if (ports != NULL) 248 { 249 while (ports->name != NULL) 250 { 251 if (ports->direction == bidirect_port 252 || ports->direction == direction) 253 { 254 if (ports->nr_ports > 0) 255 { 256 int len = strlen (ports->name); 257 if (strncmp (port_name, ports->name, len) == 0) 258 { 259 if (port_name[len] == '\0') 260 return ports->number; 261 else if (isdigit (port_name[len])) 262 { 263 int port = (ports->number 264 + strtoul (&port_name[len], NULL, 0)); 265 if (port >= ports->number + ports->nr_ports) 266 hw_abort (me, 267 "Port %s out of range", 268 port_name); 269 return port; 270 } 271 } 272 } 273 else if (strcmp (port_name, ports->name) == 0) 274 return ports->number; 275 } 276 ports++; 277 } 278 } 279 } 280 hw_abort (me, "Unrecognized port %s", port_name); 281 return 0; 282} 283 284 285int 286hw_port_encode (struct hw *me, 287 int port_number, 288 char *buf, 289 int sizeof_buf, 290 port_direction direction) 291{ 292 const struct hw_port_descriptor *ports = NULL; 293 ports = me->ports_of_hw->ports; 294 if (ports != NULL) { 295 while (ports->name != NULL) 296 { 297 if (ports->direction == bidirect_port 298 || ports->direction == direction) 299 { 300 if (ports->nr_ports > 0) 301 { 302 if (port_number >= ports->number 303 && port_number < ports->number + ports->nr_ports) 304 { 305 strcpy (buf, ports->name); 306 sprintf (buf + strlen (buf), "%d", port_number - ports->number); 307 if (strlen (buf) >= sizeof_buf) 308 hw_abort (me, "hw_port_encode: buffer overflow"); 309 return strlen (buf); 310 } 311 } 312 else 313 { 314 if (ports->number == port_number) 315 { 316 if (strlen (ports->name) >= sizeof_buf) 317 hw_abort (me, "hw_port_encode: buffer overflow"); 318 strcpy (buf, ports->name); 319 return strlen (buf); 320 } 321 } 322 } 323 ports++; 324 } 325 } 326 sprintf (buf, "%d", port_number); 327 if (strlen (buf) >= sizeof_buf) 328 hw_abort (me, "hw_port_encode: buffer overflow"); 329 return strlen (buf); 330} 331