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