xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/device_table.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _DEVICE_TABLE_C_
22 #define _DEVICE_TABLE_C_
23 
24 #include "device_table.h"
25 
26 #if HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29 
30 #include <ctype.h>
31 
32 
33 /* Helper functions */
34 
35 
36 /* Go through the devices various reg properties for those that
37    specify attach addresses */
38 
39 
40 void
41 generic_device_init_address(device *me)
42 {
43   static const char *(reg_property_names[]) = {
44     "attach-addresses",
45     "assigned-addresses",
46     "reg",
47     "alternate-reg" ,
48     NULL
49   };
50   const char **reg_property_name;
51   int nr_valid_reg_properties = 0;
52   for (reg_property_name = reg_property_names;
53        *reg_property_name != NULL;
54        reg_property_name++) {
55     if (device_find_property(me, *reg_property_name) != NULL) {
56       reg_property_spec reg;
57       int reg_entry;
58       for (reg_entry = 0;
59 	   device_find_reg_array_property(me, *reg_property_name, reg_entry,
60 					  &reg);
61 	   reg_entry++) {
62 	unsigned_word attach_address;
63 	int attach_space;
64 	unsigned attach_size;
65 	if (!device_address_to_attach_address(device_parent(me),
66 					      &reg.address,
67 					      &attach_space, &attach_address,
68 					      me))
69 	  continue;
70 	if (!device_size_to_attach_size(device_parent(me),
71 					&reg.size,
72 					&attach_size, me))
73 	  continue;
74 	device_attach_address(device_parent(me),
75 			      attach_callback,
76 			      attach_space, attach_address, attach_size,
77 			      access_read_write_exec,
78 			      me);
79 	nr_valid_reg_properties++;
80       }
81       /* if first option matches don't try for any others */
82       if (reg_property_name == reg_property_names)
83 	break;
84     }
85   }
86 }
87 
88 int
89 generic_device_unit_decode(device *bus,
90 			   const char *unit,
91 			   device_unit *phys)
92 {
93   memset(phys, 0, sizeof(device_unit));
94   if (unit == NULL)
95     return 0;
96   else {
97     int nr_cells = 0;
98     const int max_nr_cells = device_nr_address_cells(bus);
99     while (1) {
100       char *end = NULL;
101       unsigned long val;
102       val = strtoul(unit, &end, 0);
103       /* parse error? */
104       if (unit == end)
105 	return -1;
106       /* two many cells? */
107       if (nr_cells >= max_nr_cells)
108 	return -1;
109       /* save it */
110       phys->cells[nr_cells] = val;
111       nr_cells++;
112       unit = end;
113       /* more to follow? */
114       if (isspace(*unit) || *unit == '\0')
115 	break;
116       if (*unit != ',')
117 	return -1;
118       unit++;
119     }
120     if (nr_cells < max_nr_cells) {
121       /* shift everything to correct position */
122       int i;
123       for (i = 1; i <= nr_cells; i++)
124 	phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
125       for (i = 0; i < (max_nr_cells - nr_cells); i++)
126 	phys->cells[i] = 0;
127     }
128     phys->nr_cells = max_nr_cells;
129     return max_nr_cells;
130   }
131 }
132 
133 int
134 generic_device_unit_encode(device *bus,
135 			   const device_unit *phys,
136 			   char *buf,
137 			   int sizeof_buf)
138 {
139   int i;
140   int len;
141   char *pos = buf;
142   /* skip leading zero's */
143   for (i = 0; i < phys->nr_cells; i++) {
144     if (phys->cells[i] != 0)
145       break;
146   }
147   /* don't output anything if empty */
148   if (phys->nr_cells == 0) {
149     strcpy(pos, "");
150     len = 0;
151   }
152   else if (i == phys->nr_cells) {
153     /* all zero */
154     strcpy(pos, "0");
155     len = 1;
156   }
157   else {
158     for (; i < phys->nr_cells; i++) {
159       if (pos != buf) {
160 	strcat(pos, ",");
161 	pos = strchr(pos, '\0');
162       }
163       if (phys->cells[i] < 10)
164 	sprintf(pos, "%ld", (unsigned long)phys->cells[i]);
165       else
166 	sprintf(pos, "0x%lx", (unsigned long)phys->cells[i]);
167       pos = strchr(pos, '\0');
168     }
169     len = pos - buf;
170   }
171   if (len >= sizeof_buf)
172     error("generic_unit_encode - buffer overflow\n");
173   return len;
174 }
175 
176 int
177 generic_device_address_to_attach_address(device *me,
178 					 const device_unit *address,
179 					 int *attach_space,
180 					 unsigned_word *attach_address,
181 					 device *client)
182 {
183   int i;
184   for (i = 0; i < address->nr_cells - 2; i++) {
185     if (address->cells[i] != 0)
186       device_error(me, "Only 32bit addresses supported");
187   }
188   if (address->nr_cells >= 2)
189     *attach_space = address->cells[address->nr_cells - 2];
190   else
191     *attach_space = 0;
192   *attach_address = address->cells[address->nr_cells - 1];
193   return 1;
194 }
195 
196 int
197 generic_device_size_to_attach_size(device *me,
198 				   const device_unit *size,
199 				   unsigned *nr_bytes,
200 				   device *client)
201 {
202   int i;
203   for (i = 0; i < size->nr_cells - 1; i++) {
204     if (size->cells[i] != 0)
205       device_error(me, "Only 32bit sizes supported");
206   }
207   *nr_bytes = size->cells[0];
208   return *nr_bytes;
209 }
210 
211 
212 /* ignore/passthrough versions of each function */
213 
214 void
215 passthrough_device_address_attach(device *me,
216 				  attach_type attach,
217 				  int space,
218 				  unsigned_word addr,
219 				  unsigned nr_bytes,
220 				  access_type access,
221 				  device *client) /*callback/default*/
222 {
223   device_attach_address(device_parent(me), attach,
224 			space, addr, nr_bytes,
225 			access,
226 			client);
227 }
228 
229 void
230 passthrough_device_address_detach(device *me,
231 				  attach_type attach,
232 				  int space,
233 				  unsigned_word addr,
234 				  unsigned nr_bytes,
235 				  access_type access,
236 				  device *client) /*callback/default*/
237 {
238   device_detach_address(device_parent(me), attach,
239 			space, addr, nr_bytes, access,
240 			client);
241 }
242 
243 unsigned
244 passthrough_device_dma_read_buffer(device *me,
245 				   void *dest,
246 				   int space,
247 				   unsigned_word addr,
248 				   unsigned nr_bytes)
249 {
250   return device_dma_read_buffer(device_parent(me), dest,
251 				space, addr, nr_bytes);
252 }
253 
254 unsigned
255 passthrough_device_dma_write_buffer(device *me,
256 			     const void *source,
257 			     int space,
258 			     unsigned_word addr,
259 			     unsigned nr_bytes,
260 			     int violate_read_only_section)
261 {
262   return device_dma_write_buffer(device_parent(me), source,
263 				 space, addr,
264 				 nr_bytes,
265 				 violate_read_only_section);
266 }
267 
268 int
269 ignore_device_unit_decode(device *me,
270 			  const char *unit,
271 			  device_unit *phys)
272 {
273   memset(phys, 0, sizeof(device_unit));
274   return 0;
275 }
276 
277 
278 static const device_callbacks passthrough_callbacks = {
279   { NULL, }, /* init */
280   { passthrough_device_address_attach,
281     passthrough_device_address_detach, },
282   { NULL, }, /* IO */
283   { passthrough_device_dma_read_buffer, passthrough_device_dma_write_buffer, },
284   { NULL, }, /* interrupt */
285   { generic_device_unit_decode,
286     generic_device_unit_encode, },
287 };
288 
289 
290 static const device_descriptor ob_device_table[] = {
291   /* standard OpenBoot devices */
292   { "aliases", NULL, &passthrough_callbacks },
293   { "options", NULL, &passthrough_callbacks },
294   { "chosen", NULL, &passthrough_callbacks },
295   { "packages", NULL, &passthrough_callbacks },
296   { "cpus", NULL, &passthrough_callbacks },
297   { "openprom", NULL, &passthrough_callbacks },
298   { "init", NULL, &passthrough_callbacks },
299   { NULL },
300 };
301 
302 const device_descriptor *const device_table[] = {
303   ob_device_table,
304 #include "hw.c"
305   NULL,
306 };
307 
308 
309 #endif /* _DEVICE_TABLE_C_ */
310