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