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 40void 41generic_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 ®); 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 ®.address, 67 &attach_space, &attach_address, 68 me)) 69 continue; 70 if (!device_size_to_attach_size(device_parent(me), 71 ®.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 88int 89generic_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 133int 134generic_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 176int 177generic_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 196int 197generic_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 214void 215passthrough_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 229void 230passthrough_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 243unsigned 244passthrough_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 254unsigned 255passthrough_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 268int 269ignore_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 278static 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 290static 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 302const device_descriptor *const device_table[] = { 303 ob_device_table, 304#include "hw.c" 305 NULL, 306}; 307 308 309#endif /* _DEVICE_TABLE_C_ */ 310