1 /* Hardware ports. 2 Copyright (C) 1998-2024 Free Software Foundation, Inc. 3 Contributed by Andrew Cagney and Cygnus Solutions. 4 5 This file is part of GDB, the GNU debugger. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along 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 30 struct 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 39 struct 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 46 const struct hw_port_descriptor empty_hw_ports[] = 47 { 48 { NULL, 0, 0, 0 }, 49 }; 50 51 static void 52 panic_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 61 void 62 create_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 69 void 70 delete_hw_port_data (struct hw *me) 71 { 72 hw_free (me, me->ports_of_hw); 73 me->ports_of_hw = NULL; 74 } 75 76 void 77 set_hw_ports (struct hw *me, 78 const struct hw_port_descriptor ports[]) 79 { 80 me->ports_of_hw->ports = ports; 81 } 82 83 void 84 set_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 91 static void 92 attach_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 109 static void 110 detach_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 == permanent_object) 124 hw_abort (me, "attempt to delete permanent 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 135 static void 136 clean_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 permanent_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 158 void 159 hw_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 185 void 186 hw_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 201 void 202 hw_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 215 void 216 hw_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 232 int 233 hw_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 285 int 286 hw_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