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 ®); 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 ®.address, 63 &attach_space, &attach_address, 64 me)) 65 continue; 66 if (!device_size_to_attach_size(device_parent(me), 67 ®.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