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 ®); 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 ®.address, 68 &attach_space, &attach_address, 69 me)) 70 continue; 71 if (!device_size_to_attach_size(device_parent(me), 72 ®.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