/* This file is part of the program psim. Copyright (C) 1994-1996, Andrew Cagney This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DEVICE_TABLE_C_ #define _DEVICE_TABLE_C_ #include "device_table.h" #if HAVE_STDLIB_H #include #endif #include /* Helper functions */ /* Go through the devices various reg properties for those that specify attach addresses */ void generic_device_init_address(device *me) { static const char *(reg_property_names[]) = { "attach-addresses", "assigned-addresses", "reg", "alternate-reg" , NULL }; const char **reg_property_name; int nr_valid_reg_properties = 0; for (reg_property_name = reg_property_names; *reg_property_name != NULL; reg_property_name++) { if (device_find_property(me, *reg_property_name) != NULL) { reg_property_spec reg; int reg_entry; for (reg_entry = 0; device_find_reg_array_property(me, *reg_property_name, reg_entry, ®); reg_entry++) { unsigned_word attach_address; int attach_space; unsigned attach_size; if (!device_address_to_attach_address(device_parent(me), ®.address, &attach_space, &attach_address, me)) continue; if (!device_size_to_attach_size(device_parent(me), ®.size, &attach_size, me)) continue; device_attach_address(device_parent(me), attach_callback, attach_space, attach_address, attach_size, access_read_write_exec, me); nr_valid_reg_properties++; } /* if first option matches don't try for any others */ if (reg_property_name == reg_property_names) break; } } } int generic_device_unit_decode(device *bus, const char *unit, device_unit *phys) { memset(phys, 0, sizeof(device_unit)); if (unit == NULL) return 0; else { int nr_cells = 0; const int max_nr_cells = device_nr_address_cells(bus); while (1) { char *end = NULL; unsigned long val; val = strtoul(unit, &end, 0); /* parse error? */ if (unit == end) return -1; /* two many cells? */ if (nr_cells >= max_nr_cells) return -1; /* save it */ phys->cells[nr_cells] = val; nr_cells++; unit = end; /* more to follow? */ if (isspace(*unit) || *unit == '\0') break; if (*unit != ',') return -1; unit++; } if (nr_cells < max_nr_cells) { /* shift everything to correct position */ int i; for (i = 1; i <= nr_cells; i++) phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i]; for (i = 0; i < (max_nr_cells - nr_cells); i++) phys->cells[i] = 0; } phys->nr_cells = max_nr_cells; return max_nr_cells; } } int generic_device_unit_encode(device *bus, const device_unit *phys, char *buf, int sizeof_buf) { int i; int len; char *pos = buf; /* skip leading zero's */ for (i = 0; i < phys->nr_cells; i++) { if (phys->cells[i] != 0) break; } /* don't output anything if empty */ if (phys->nr_cells == 0) { strcpy(pos, ""); len = 0; } else if (i == phys->nr_cells) { /* all zero */ strcpy(pos, "0"); len = 1; } else { for (; i < phys->nr_cells; i++) { if (pos != buf) { strcat(pos, ","); pos = strchr(pos, '\0'); } if (phys->cells[i] < 10) sprintf(pos, "%ld", (unsigned long)phys->cells[i]); else sprintf(pos, "0x%lx", (unsigned long)phys->cells[i]); pos = strchr(pos, '\0'); } len = pos - buf; } if (len >= sizeof_buf) error("generic_unit_encode - buffer overflow\n"); return len; } int generic_device_address_to_attach_address(device *me, const device_unit *address, int *attach_space, unsigned_word *attach_address, device *client) { int i; for (i = 0; i < address->nr_cells - 2; i++) { if (address->cells[i] != 0) device_error(me, "Only 32bit addresses supported"); } if (address->nr_cells >= 2) *attach_space = address->cells[address->nr_cells - 2]; else *attach_space = 0; *attach_address = address->cells[address->nr_cells - 1]; return 1; } int generic_device_size_to_attach_size(device *me, const device_unit *size, unsigned *nr_bytes, device *client) { int i; for (i = 0; i < size->nr_cells - 1; i++) { if (size->cells[i] != 0) device_error(me, "Only 32bit sizes supported"); } *nr_bytes = size->cells[0]; return *nr_bytes; } /* ignore/passthrough versions of each function */ void passthrough_device_address_attach(device *me, attach_type attach, int space, unsigned_word addr, unsigned nr_bytes, access_type access, device *client) /*callback/default*/ { device_attach_address(device_parent(me), attach, space, addr, nr_bytes, access, client); } void passthrough_device_address_detach(device *me, attach_type attach, int space, unsigned_word addr, unsigned nr_bytes, access_type access, device *client) /*callback/default*/ { device_detach_address(device_parent(me), attach, space, addr, nr_bytes, access, client); } unsigned passthrough_device_dma_read_buffer(device *me, void *dest, int space, unsigned_word addr, unsigned nr_bytes) { return device_dma_read_buffer(device_parent(me), dest, space, addr, nr_bytes); } unsigned passthrough_device_dma_write_buffer(device *me, const void *source, int space, unsigned_word addr, unsigned nr_bytes, int violate_read_only_section) { return device_dma_write_buffer(device_parent(me), source, space, addr, nr_bytes, violate_read_only_section); } int ignore_device_unit_decode(device *me, const char *unit, device_unit *phys) { memset(phys, 0, sizeof(device_unit)); return 0; } static const device_callbacks passthrough_callbacks = { { NULL, }, /* init */ { passthrough_device_address_attach, passthrough_device_address_detach, }, { NULL, }, /* IO */ { passthrough_device_dma_read_buffer, passthrough_device_dma_write_buffer, }, { NULL, }, /* interrupt */ { generic_device_unit_decode, generic_device_unit_encode, }, }; static const device_descriptor ob_device_table[] = { /* standard OpenBoot devices */ { "aliases", NULL, &passthrough_callbacks }, { "options", NULL, &passthrough_callbacks }, { "chosen", NULL, &passthrough_callbacks }, { "packages", NULL, &passthrough_callbacks }, { "cpus", NULL, &passthrough_callbacks }, { "openprom", NULL, &passthrough_callbacks }, { "init", NULL, &passthrough_callbacks }, { NULL }, }; const device_descriptor *const device_table[] = { ob_device_table, #include "hw.c" NULL, }; #endif /* _DEVICE_TABLE_C_ */