1 /* Hardware ports. 2 Copyright (C) 1998-2019 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 21 #include "hw-main.h" 22 #include "hw-base.h" 23 24 #ifdef HAVE_STDLIB_H 25 #include <stdlib.h> 26 #endif 27 28 #ifdef HAVE_STRING_H 29 #include <string.h> 30 #else 31 #ifdef HAVE_STRINGS_H 32 #include <strings.h> 33 #endif 34 #endif 35 36 #include <ctype.h> 37 38 39 struct hw_port_edge 40 { 41 int my_port; 42 struct hw *dest; 43 int dest_port; 44 struct hw_port_edge *next; 45 object_disposition disposition; 46 }; 47 48 struct hw_port_data 49 { 50 hw_port_event_method *to_port_event; 51 const struct hw_port_descriptor *ports; 52 struct hw_port_edge *edges; 53 }; 54 55 const struct hw_port_descriptor empty_hw_ports[] = 56 { 57 { NULL, 0, 0, 0 }, 58 }; 59 60 static void 61 panic_hw_port_event (struct hw *me, 62 int my_port, 63 struct hw *source, 64 int source_port, 65 int level) 66 { 67 hw_abort (me, "no port method"); 68 } 69 70 void 71 create_hw_port_data (struct hw *me) 72 { 73 me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data); 74 set_hw_port_event (me, panic_hw_port_event); 75 set_hw_ports (me, empty_hw_ports); 76 } 77 78 void 79 delete_hw_port_data (struct hw *me) 80 { 81 hw_free (me, me->ports_of_hw); 82 me->ports_of_hw = NULL; 83 } 84 85 void 86 set_hw_ports (struct hw *me, 87 const struct hw_port_descriptor ports[]) 88 { 89 me->ports_of_hw->ports = ports; 90 } 91 92 void 93 set_hw_port_event (struct hw *me, 94 hw_port_event_method *port_event) 95 { 96 me->ports_of_hw->to_port_event = port_event; 97 } 98 99 100 static void 101 attach_hw_port_edge (struct hw *me, 102 struct hw_port_edge **list, 103 int my_port, 104 struct hw *dest, 105 int dest_port, 106 object_disposition disposition) 107 { 108 struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge); 109 new_edge->my_port = my_port; 110 new_edge->dest = dest; 111 new_edge->dest_port = dest_port; 112 new_edge->next = *list; 113 new_edge->disposition = disposition; 114 *list = new_edge; 115 } 116 117 118 static void 119 detach_hw_port_edge (struct hw *me, 120 struct hw_port_edge **list, 121 int my_port, 122 struct hw *dest, 123 int dest_port) 124 { 125 while (*list != NULL) 126 { 127 struct hw_port_edge *old_edge = *list; 128 if (old_edge->dest == dest 129 && old_edge->dest_port == dest_port 130 && old_edge->my_port == my_port) 131 { 132 if (old_edge->disposition == permenant_object) 133 hw_abort (me, "attempt to delete permenant port edge"); 134 *list = old_edge->next; 135 hw_free (me, old_edge); 136 return; 137 } 138 } 139 hw_abort (me, "attempt to delete unattached port"); 140 } 141 142 143 #if 0 144 static void 145 clean_hw_port_edges (struct hw_port_edge **list) 146 { 147 while (*list != NULL) 148 { 149 struct hw_port_edge *old_edge = *list; 150 switch (old_edge->disposition) 151 { 152 case permenant_object: 153 list = &old_edge->next; 154 break; 155 case temporary_object: 156 *list = old_edge->next; 157 hw_free (me, old_edge); 158 break; 159 } 160 } 161 } 162 #endif 163 164 165 /* Ports: */ 166 167 void 168 hw_port_event (struct hw *me, 169 int my_port, 170 int level) 171 { 172 int found_an_edge = 0; 173 struct hw_port_edge *edge; 174 /* device's lines directly connected */ 175 for (edge = me->ports_of_hw->edges; 176 edge != NULL; 177 edge = edge->next) 178 { 179 if (edge->my_port == my_port) 180 { 181 edge->dest->ports_of_hw->to_port_event (edge->dest, 182 edge->dest_port, 183 me, 184 my_port, 185 level); 186 found_an_edge = 1; 187 } 188 } 189 if (!found_an_edge) 190 hw_abort (me, "No edge for port %d", my_port); 191 } 192 193 194 void 195 hw_port_attach (struct hw *me, 196 int my_port, 197 struct hw *dest, 198 int dest_port, 199 object_disposition disposition) 200 { 201 attach_hw_port_edge (me, 202 &me->ports_of_hw->edges, 203 my_port, 204 dest, 205 dest_port, 206 disposition); 207 } 208 209 210 void 211 hw_port_detach (struct hw *me, 212 int my_port, 213 struct hw *dest, 214 int dest_port) 215 { 216 detach_hw_port_edge (me, 217 &me->ports_of_hw->edges, 218 my_port, 219 dest, 220 dest_port); 221 } 222 223 224 void 225 hw_port_traverse (struct hw *me, 226 hw_port_traverse_function *handler, 227 void *data) 228 { 229 struct hw_port_edge *port_edge; 230 for (port_edge = me->ports_of_hw->edges; 231 port_edge != NULL; 232 port_edge = port_edge->next) 233 { 234 handler (me, port_edge->my_port, 235 port_edge->dest, port_edge->dest_port, 236 data); 237 } 238 } 239 240 241 int 242 hw_port_decode (struct hw *me, 243 const char *port_name, 244 port_direction direction) 245 { 246 if (port_name == NULL || port_name[0] == '\0') 247 return 0; 248 if (isdigit (port_name[0])) 249 { 250 return strtoul (port_name, NULL, 0); 251 } 252 else 253 { 254 const struct hw_port_descriptor *ports = 255 me->ports_of_hw->ports; 256 if (ports != NULL) 257 { 258 while (ports->name != NULL) 259 { 260 if (ports->direction == bidirect_port 261 || ports->direction == direction) 262 { 263 if (ports->nr_ports > 0) 264 { 265 int len = strlen (ports->name); 266 if (strncmp (port_name, ports->name, len) == 0) 267 { 268 if (port_name[len] == '\0') 269 return ports->number; 270 else if (isdigit (port_name[len])) 271 { 272 int port = (ports->number 273 + strtoul (&port_name[len], NULL, 0)); 274 if (port >= ports->number + ports->nr_ports) 275 hw_abort (me, 276 "Port %s out of range", 277 port_name); 278 return port; 279 } 280 } 281 } 282 else if (strcmp (port_name, ports->name) == 0) 283 return ports->number; 284 } 285 ports++; 286 } 287 } 288 } 289 hw_abort (me, "Unrecognized port %s", port_name); 290 return 0; 291 } 292 293 294 int 295 hw_port_encode (struct hw *me, 296 int port_number, 297 char *buf, 298 int sizeof_buf, 299 port_direction direction) 300 { 301 const struct hw_port_descriptor *ports = NULL; 302 ports = me->ports_of_hw->ports; 303 if (ports != NULL) { 304 while (ports->name != NULL) 305 { 306 if (ports->direction == bidirect_port 307 || ports->direction == direction) 308 { 309 if (ports->nr_ports > 0) 310 { 311 if (port_number >= ports->number 312 && port_number < ports->number + ports->nr_ports) 313 { 314 strcpy (buf, ports->name); 315 sprintf (buf + strlen (buf), "%d", port_number - ports->number); 316 if (strlen (buf) >= sizeof_buf) 317 hw_abort (me, "hw_port_encode: buffer overflow"); 318 return strlen (buf); 319 } 320 } 321 else 322 { 323 if (ports->number == port_number) 324 { 325 if (strlen (ports->name) >= sizeof_buf) 326 hw_abort (me, "hw_port_encode: buffer overflow"); 327 strcpy (buf, ports->name); 328 return strlen (buf); 329 } 330 } 331 } 332 ports++; 333 } 334 } 335 sprintf (buf, "%d", port_number); 336 if (strlen (buf) >= sizeof_buf) 337 hw_abort (me, "hw_port_encode: buffer overflow"); 338 return strlen (buf); 339 } 340