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
41void
42generic_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
89int
90generic_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
134int
135generic_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
177int
178generic_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
197int
198generic_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
215void
216passthrough_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
230void
231passthrough_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
244unsigned
245passthrough_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
255unsigned
256passthrough_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
269int
270ignore_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
279static 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
291static 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
303const device_descriptor *const device_table[] = {
304  ob_device_table,
305#include "hw.c"
306  NULL,
307};
308
309
310#endif /* _DEVICE_TABLE_C_ */
311