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