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