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