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