1 /* Hardware ports.
2 Copyright (C) 1998-2013 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
panic_hw_port_event(struct hw * me,int my_port,struct hw * source,int source_port,int level)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
create_hw_port_data(struct hw * me)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
delete_hw_port_data(struct hw * me)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
set_hw_ports(struct hw * me,const struct hw_port_descriptor ports[])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
set_hw_port_event(struct hw * me,hw_port_event_method * port_event)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
attach_hw_port_edge(struct hw * me,struct hw_port_edge ** list,int my_port,struct hw * dest,int dest_port,object_disposition disposition)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
detach_hw_port_edge(struct hw * me,struct hw_port_edge ** list,int my_port,struct hw * dest,int dest_port)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
hw_port_event(struct hw * me,int my_port,int level)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
hw_port_attach(struct hw * me,int my_port,struct hw * dest,int dest_port,object_disposition disposition)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
hw_port_detach(struct hw * me,int my_port,struct hw * dest,int dest_port)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
hw_port_traverse(struct hw * me,hw_port_traverse_function * handler,void * data)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
hw_port_decode(struct hw * me,const char * port_name,port_direction direction)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
hw_port_encode(struct hw * me,int port_number,char * buf,int sizeof_buf,port_direction direction)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