void hw_finish (struct hw *me) { if (hw_finished_p (me)) hw_abort (me, "Attempt to finish finished device"); /* Fill in the (hopefully) defined address/size cells values */ if (hw_find_property (me, "#address-cells") != NULL) me->nr_address_cells_of_hw_unit = hw_find_integer_property (me, "#address-cells"); else me->nr_address_cells_of_hw_unit = 2; if (hw_find_property (me, "#size-cells") != NULL) me->nr_size_cells_of_hw_unit = hw_find_integer_property (me, "#size-cells"); else me->nr_size_cells_of_hw_unit = 1; /* Fill in the (hopefully) defined trace variable */ if (hw_find_property (me, "trace?") != NULL) me->trace_of_hw_p = hw_find_boolean_property (me, "trace?"); /* allow global variable to define default tracing */ else if (! hw_trace_p (me) && hw_find_property (hw_root (me), "global-trace?") != NULL && hw_find_boolean_property (hw_root (me), "global-trace?")) me->trace_of_hw_p = 1; /* Allow the real device to override any methods */ me->base_of_hw->descriptor->to_finish (me); me->base_of_hw->finished_p = 1; }
static void attach_mn103cpu_regs (struct hw *me, struct mn103cpu *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); controller->block.base = attach_address; hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); controller->block.bound = attach_address + (attach_size - 1); if ((controller->block.base & 3) != 0) hw_abort (me, "cpu register block must be 4 byte aligned"); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); }
int hw_find_integer_array_property (struct hw *me, const char *property, unsigned index, signed_cell *integer) { const struct hw_property *node; int sizeof_integer = sizeof (*integer); signed_cell *cell; TRACE (trace_devices, ("hw_find_integer(me=0x%lx, property=%s)\n", (long)me, property)); /* check things sane */ node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != integer_property && node->type != array_property) hw_abort (me, "property \"%s\" of wrong type (integer or array)", property); if ((node->sizeof_array % sizeof_integer) != 0) hw_abort (me, "property \"%s\" contains an incomplete number of cells", property); if (node->sizeof_array <= sizeof_integer * index) return 0; /* Find and convert the value */ cell = ((signed_cell*)node->array) + index; *integer = BE2H_cell (*cell); return node->sizeof_array / sizeof_integer; }
static void attach_tx3904irc_regs (struct hw *me, struct tx3904irc *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); controller->base_address = attach_address; }
static void hw_pal_finish (struct hw *hw) { /* create the descriptor */ hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device); hw_pal->output.status = 1; hw_pal->output.buffer = '\0'; hw_pal->input.status = 0; hw_pal->input.buffer = '\0'; set_hw_data (hw, hw_pal); set_hw_attach_address (hw, hw_pal_attach_address); set_hw_io_read_buffer (hw, hw_pal_io_read_buffer); set_hw_io_write_buffer (hw, hw_pal_io_write_buffer); set_hw_ports (hw, hw_pal_ports); /* attach ourselves */ do_hw_attach_regs (hw); /* If so configured, enable polled input */ if (hw_find_property (hw, "poll?") != NULL && hw_find_boolean_property (hw, "poll?")) { hw_pal->reader = sim_io_poll_read; } else { hw_pal->reader = sim_io_read; } /* tag the periodic timer */ hw_pal->timer.periodic_p = 1; }
static void attach_bfin_cec_regs (struct hw *me, struct bfin_cec *cec) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); if (attach_size != BFIN_COREMMR_CEC_SIZE) hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_CEC_SIZE); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); cec->base = attach_address; /* XXX: should take from the device tree. */ cec->cpu = STATE_CPU (hw_system (me), 0); cec->me = me; }
static void attach_mn103ser_regs (struct hw *me, struct mn103ser *serial) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); serial->block.base = attach_address; hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); serial->block.bound = attach_address + (attach_size - 1); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); }
static void attach_mn103iop_regs (struct hw *me, struct mn103iop *io_port) { int i; unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); for (i=0; i < NR_BLOCKS; ++i ) { if (!hw_find_reg_array_property (me, "reg", i, ®)) hw_abort (me, "\"reg\" property must contain five addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); io_port->block[i].base = attach_address; hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); io_port->block[i].bound = attach_address + (attach_size - 1); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); } }
static void attach_bfin_ppi_regs (struct hw *me, struct bfin_ppi *ppi) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); if (attach_size != BFIN_MMR_PPI_SIZE) hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PPI_SIZE); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); ppi->base = attach_address; }
static void attach_m68hc11eepr_regs (struct hw *me, struct m68hc11eepr *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); /* Attach the two IO registers that control the EEPROM. The EEPROM is only attached at reset time because it may be enabled/disabled by the EEON bit in the CONFIG register. */ hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_PPROG, 1, me); hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_CONFIG, 1, me); if (hw_find_property (me, "file") == NULL) controller->file_name = "m6811.eeprom"; else controller->file_name = hw_find_string_property (me, "file"); controller->attach_space = attach_space; controller->base_address = attach_address; controller->eeprom = (char*) hw_malloc (me, attach_size + 1); controller->eeprom_min_cycles = 10000; controller->size = attach_size + 1; controller->mapped = 0; m6811eepr_memory_rw (controller, O_RDONLY); }
static void attach_tx3904sio_regs (struct hw *me, struct tx3904sio *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); if(hw_find_property(me, "backend") != NULL) { const char* value = hw_find_string_property(me, "backend"); if(! strcmp(value, "tcp")) controller->backend = sio_tcp; else if(! strcmp(value, "stdio")) controller->backend = sio_stdio; else hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value); } controller->base_address = attach_address; }
const struct hw_property * hw_find_array_property (struct hw *me, const char *property) { const struct hw_property *node; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != array_property) hw_abort (me, "property \"%s\" of wrong type (array)", property); return node; }
const struct hw_property * hw_tree_find_property (struct hw *root, const char *path_to_property) { name_specifier spec; if (!split_property_specifier (root, path_to_property, &spec)) hw_abort (root, "Invalid property path %s", path_to_property); root = split_find_device (root, &spec); if (spec.name != NULL) return NULL; /* not a leaf */ return hw_find_property (root, spec.property); }
void do_hw_attach_regs (struct hw *hw) { 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 (hw_find_property (hw, *reg_property_name) != NULL) { reg_property_spec reg; int reg_entry; for (reg_entry = 0; hw_find_reg_array_property (hw, *reg_property_name, reg_entry, ®); reg_entry++) { unsigned_word attach_address; int attach_space; unsigned attach_size; if (!hw_unit_address_to_attach_address (hw_parent (hw), ®.address, &attach_space, &attach_address, hw)) continue; if (!hw_unit_size_to_attach_size (hw_parent (hw), ®.size, &attach_size, hw)) continue; hw_attach_address (hw_parent (hw), 0, attach_space, attach_address, attach_size, hw); nr_valid_reg_properties++; } /* if first option matches don't try for any others */ if (reg_property_name == reg_property_names) break; } } }
const char * hw_find_string_property (struct hw *me, const char *property) { const struct hw_property *node; const char *string; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != string_property) hw_abort (me, "property \"%s\" of wrong type (string)", property); string = node->array; ASSERT (strlen(string) + 1 == node->sizeof_array); return string; }
int hw_find_boolean_property (struct hw *me, const char *property) { const struct hw_property *node; unsigned_cell boolean; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != boolean_property) hw_abort (me, "property \"%s\" of wrong type (boolean)", property); ASSERT (sizeof (boolean) == node->sizeof_array); memcpy (&boolean, node->array, sizeof (boolean)); return boolean; }
signed_cell hw_find_integer_property (struct hw *me, const char *property) { const struct hw_property *node; signed_cell integer; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != integer_property) hw_abort (me, "property \"%s\" of wrong type (integer)", property); ASSERT (sizeof (integer) == node->sizeof_array); memcpy (&integer, node->array, sizeof (integer)); return BE2H_cell (integer); }
int hw_find_range_array_property (struct hw *me, const char *property, unsigned index, range_property_spec *range) { const struct hw_property *node; unsigned sizeof_entry = (nr_range_property_cells (me, 1) * sizeof (unsigned_cell)); const unsigned_cell *cells; /* locate the property */ node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != range_array_property) hw_abort (me, "property \"%s\" of wrong type (range array)", property); /* aligned ? */ if ((node->sizeof_array % sizeof_entry) != 0) hw_abort (me, "property \"%s\" contains an incomplete number of entries", property); /* within bounds? */ if (node->sizeof_array < sizeof_entry * (index + 1)) return 0; /* find the range of interest */ cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); /* copy the child address out - converting as we go */ cells = cells_to_unit_address (cells, &range->child_address, hw_unit_nr_address_cells (me)); /* copy the parent address out - converting as we go */ cells = cells_to_unit_address (cells, &range->parent_address, hw_unit_nr_address_cells (hw_parent (me))); /* copy the size - converting as we go */ cells = cells_to_unit_address (cells, &range->size, hw_unit_nr_size_cells (me)); return node->sizeof_array / sizeof_entry; }
static void attach_m68hc11sio_regs (struct hw *me, struct m68hc11sio *controller) { hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_SCI_FIRST_REG, M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1, me); if (hw_find_property(me, "backend") != NULL) { const char *value = hw_find_string_property(me, "backend"); if(! strcmp(value, "tcp")) controller->backend = sio_tcp; else if(! strcmp(value, "stdio")) controller->backend = sio_stdio; else hw_abort (me, "illegal value for backend parameter `%s':" "use tcp or stdio", value); } }
hw_instance * hw_find_ihandle_property (struct hw *me, const char *property) { const hw_property_data *node; unsigned_cell ihandle; hw_instance *instance; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != ihandle_property) hw_abort(me, "property \"%s\" of wrong type (ihandle)", property); if (node->array == NULL) hw_abort(me, "runtime property \"%s\" not yet initialized", property); ASSERT (sizeof(ihandle) == node->sizeof_array); memcpy (&ihandle, node->array, sizeof(ihandle)); instance = external_to_hw_instance (me, BE2H_cell(ihandle)); ASSERT (instance != NULL); return instance; }
static void mn103ser_finish (struct hw *me) { struct mn103ser *serial; int i; serial = HW_ZALLOC (me, struct mn103ser); set_hw_data (me, serial); set_hw_io_read_buffer (me, mn103ser_io_read_buffer); set_hw_io_write_buffer (me, mn103ser_io_write_buffer); set_hw_ports (me, mn103ser_ports); /* Attach ourself to our parent bus */ attach_mn103ser_regs (me, serial); /* If so configured, enable polled input */ if (hw_find_property (me, "poll?") != NULL && hw_find_boolean_property (me, "poll?")) { serial->reader = sim_io_poll_read; } else { serial->reader = sim_io_read; } /* Initialize the serial device registers. */ for ( i=0; i<NR_SERIAL_DEVS; ++i ) { serial->device[i].txb = 0; serial->device[i].rxb = 0; serial->device[i].status = 0; serial->device[i].control = 0; serial->device[i].intmode = 0; serial->device[i].event = NULL; } }
static void bfin_ppi_finish (struct hw *me) { struct bfin_ppi *ppi; const char *color; ppi = HW_ZALLOC (me, struct bfin_ppi); set_hw_data (me, ppi); set_hw_io_read_buffer (me, bfin_ppi_io_read_buffer); set_hw_io_write_buffer (me, bfin_ppi_io_write_buffer); set_hw_dma_read_buffer (me, bfin_ppi_dma_read_buffer); set_hw_dma_write_buffer (me, bfin_ppi_dma_write_buffer); set_hw_ports (me, bfin_ppi_ports); attach_bfin_ppi_regs (me, ppi); /* Initialize the PPI. */ if (hw_find_property (me, "color")) color = hw_find_string_property (me, "color"); else color = NULL; ppi->color = bfin_gui_color (color); }
/* Device tree options: Required: .../reg <addr> <len> .../cmdset <primary; integer> [alt; integer] Optional: .../size <device size (must be pow of 2)> .../width <8|16|32> .../write_size <integer (must be pow of 2)> .../erase_regions <number blocks> <block size> \ [<number blocks> <block size> ...] .../voltage <vcc min> <vcc max> <vpp min> <vpp max> .../timeouts <typ unit write> <typ buf write> \ <typ block erase> <typ chip erase> \ <max unit write> <max buf write> \ <max block erase> <max chip erase> .../file <file> [ro|rw] Defaults: size: <len> from "reg" width: 8 write_size: 0 (not supported) erase_region: 1 (can only erase whole chip) voltage: 0.0V (for all) timeouts: typ: 1µs, not supported, 1ms, not supported max: 1µs, 1ms, 1ms, not supported TODO: Verify user args are valid (e.g. voltage is 8 bits). */ static void attach_cfi_regs (struct hw *me, struct cfi *cfi) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; bool fd_writable; int i, ret, fd; signed_cell ival; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (hw_find_property (me, "cmdset") == NULL) hw_abort (me, "Missing \"cmdset\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); /* Extract the desired flash command set. */ ret = hw_find_integer_array_property (me, "cmdset", 0, &ival); if (ret != 1 && ret != 2) hw_abort (me, "\"cmdset\" property takes 1 or 2 entries"); cfi_encode_16bit (cfi->query.p_id, ival); for (i = 0; i < ARRAY_SIZE (cfi_cmdsets); ++i) if (cfi_cmdsets[i]->id == ival) cfi->cmdset = cfi_cmdsets[i]; if (cfi->cmdset == NULL) hw_abort (me, "cmdset %u not supported", ival); if (ret == 2) { hw_find_integer_array_property (me, "cmdset", 1, &ival); cfi_encode_16bit (cfi->query.a_id, ival); } /* Extract the desired device size. */ if (hw_find_property (me, "size")) cfi->dev_size = hw_find_integer_property (me, "size"); else cfi->dev_size = attach_size; cfi->query.dev_size = log2 (cfi->dev_size); /* Extract the desired flash width. */ if (hw_find_property (me, "width")) { cfi->width = hw_find_integer_property (me, "width"); if (cfi->width != 8 && cfi->width != 16 && cfi->width != 32) hw_abort (me, "\"width\" must be 8 or 16 or 32, not %u", cfi->width); } else /* Default to 8 bit. */ cfi->width = 8; /* Turn 8/16/32 into 1/2/4. */ cfi->width /= 8; /* Extract optional write buffer size. */ if (hw_find_property (me, "write_size")) { ival = hw_find_integer_property (me, "write_size"); cfi_encode_16bit (cfi->query.max_buf_write_len, log2 (ival)); } /* Extract optional erase regions. */ if (hw_find_property (me, "erase_regions")) { ret = hw_find_integer_array_property (me, "erase_regions", 0, &ival); if (ret % 2) hw_abort (me, "\"erase_regions\" must be specified in sets of 2"); cfi->erase_region_info = HW_NALLOC (me, unsigned char, ret / 2); cfi->erase_regions = HW_NALLOC (me, struct cfi_erase_region, ret / 2); for (i = 0; i < ret; i += 2) { unsigned blocks, size; hw_find_integer_array_property (me, "erase_regions", i, &ival); blocks = ival; hw_find_integer_array_property (me, "erase_regions", i + 1, &ival); size = ival; cfi_add_erase_region (me, cfi, blocks, size); } }
static void print_properties (struct hw *me, struct printer *p) { const struct hw_property *property; for (property = hw_find_property (me, NULL); property != NULL; property = hw_next_property (property)) { if (hw_parent (me) == NULL) p->print (p->file, "/%s", property->name); else p->print (p->file, "%s/%s", hw_path (me), property->name); if (property->original != NULL) { p->print (p->file, " !"); p->print (p->file, "%s/%s", hw_path (property->original->owner), property->original->name); } else { switch (property->type) { case array_property: { if ((property->sizeof_array % sizeof (signed_cell)) == 0) { unsigned_cell *w = (unsigned_cell*) property->array; int cell_nr; for (cell_nr = 0; cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); cell_nr++) { p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); } } else { unsigned8 *w = (unsigned8*)property->array; p->print (p->file, " ["); while ((char*)w - (char*)property->array < property->sizeof_array) { p->print (p->file, " 0x%2x", BE2H_1 (*w)); w++; } } break; } case boolean_property: { int b = hw_find_boolean_property(me, property->name); p->print (p->file, " %s", b ? "true" : "false"); break; } #if NOT_YET case ihandle_property: { if (property->array != NULL) { device_instance *instance = hw_find_ihandle_property (me, property->name); p->print (p->file, " *%s", device_instance_path(instance)); } else { /* not yet initialized, ask the device for the path */ ihandle_runtime_property_spec spec; hw_find_ihandle_runtime_property (me, property->name, &spec); p->print (p->file, " *%s", spec.full_path); } break; } #endif case integer_property: { unsigned_word w = hw_find_integer_property (me, property->name); p->print (p->file, " 0x%lx", (unsigned long)w); break; } case range_array_property: { print_ranges_property (me, property, p); break; } case reg_array_property: { print_reg_property (me, property, p); break; } case string_property: { const char *s = hw_find_string_property (me, property->name); print_string (me, s, p); break; } case string_array_property: { print_string_array_property (me, property, p); break; } } } p->print (p->file, "\n"); } }
int hw_find_string_array_property (struct hw *me, const char *property, unsigned index, string_property_spec *string) { const struct hw_property *node; node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); switch (node->type) { default: hw_abort (me, "property \"%s\" of wrong type", property); break; case string_property: if (index == 0) { *string = node->array; ASSERT (strlen(*string) + 1 == node->sizeof_array); return 1; } break; case array_property: if (node->sizeof_array == 0 || ((char*)node->array)[node->sizeof_array - 1] != '\0') hw_abort (me, "property \"%s\" invalid for string array", property); /* FALL THROUGH */ case string_array_property: ASSERT (node->sizeof_array > 0); ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); { const char *chp = node->array; int nr_entries = 0; /* count the number of strings, keeping an eye out for the one we're looking for */ *string = chp; do { if (*chp == '\0') { /* next string */ nr_entries++; chp++; if (nr_entries == index) *string = chp; } else { chp++; } } while (chp < (char*)node->array + node->sizeof_array); if (index < nr_entries) return nr_entries; else { *string = NULL; return 0; } } break; } return 0; }
static int split_device_specifier (struct hw *current, const char *device_specifier, name_specifier *spec) { char *chp = NULL; /* expand any leading alias if present */ if (current != NULL && *device_specifier != '\0' && *device_specifier != '.' && *device_specifier != '/') { struct hw *aliases = hw_tree_find_device (current, "/aliases"); char alias[32]; int len = 0; while (device_specifier[len] != '\0' && device_specifier[len] != '/' && device_specifier[len] != ':' && !isspace (device_specifier[len])) { alias[len] = device_specifier[len]; len++; if (len >= sizeof(alias)) hw_abort (NULL, "split_device_specifier: buffer overflow"); } alias[len] = '\0'; if (aliases != NULL && hw_find_property (aliases, alias)) { strcpy (spec->buf, hw_find_string_property(aliases, alias)); strcat (spec->buf, device_specifier + len); } else { strcpy (spec->buf, device_specifier); } } else { strcpy(spec->buf, device_specifier); } /* check no overflow */ if (strlen(spec->buf) >= sizeof(spec->buf)) hw_abort (NULL, "split_device_specifier: buffer overflow\n"); /* strip leading spaces */ chp = spec->buf; while (*chp != '\0' && isspace(*chp)) chp++; if (*chp == '\0') return 0; /* find the path and terminate it with null */ spec->path = chp; while (*chp != '\0' && !isspace(*chp)) chp++; if (*chp != '\0') { *chp = '\0'; chp++; } /* and any value */ while (*chp != '\0' && isspace(*chp)) chp++; spec->value = chp; /* now go back and chop the property off of the path */ if (spec->value[0] == '\0') { spec->property = NULL; /*not a property*/ spec->value = NULL; } else if (spec->value[0] == '>' || spec->value[0] == '<') { /* an interrupt spec */ spec->property = NULL; } else { chp = strrchr(spec->path, '/'); if (chp == NULL) { spec->property = spec->path; spec->path = strchr(spec->property, '\0'); } else { *chp = '\0'; spec->property = chp+1; } } /* and mark the rest as invalid */ spec->name = NULL; spec->family = NULL; spec->unit = NULL; spec->args = NULL; spec->last_name = NULL; spec->last_family = NULL; spec->last_unit = NULL; spec->last_args = NULL; return 1; }
static void cris_finish (struct hw *me) { struct cris_hw *crishw; const struct hw_property *vec_for_int; const struct hw_property *multiple_int; crishw = HW_ZALLOC (me, struct cris_hw); set_hw_data (me, crishw); set_hw_ports (me, cris_ports); set_hw_port_event (me, cris_port_event); vec_for_int = hw_find_property (me, "vec-for-int"); if (vec_for_int != NULL) { unsigned32 vecsize; unsigned32 i; if (hw_property_type (vec_for_int) != array_property) hw_abort (me, "property \"vec-for-int\" has the wrong type"); vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell); if ((vecsize % 2) != 0) hw_abort (me, "translation vector does not consist of even pairs"); crishw->int_to_vec = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0])); for (i = 0; i < vecsize/2; i++) { signed_cell portval_sc; signed_cell vec_sc; if (!hw_find_integer_array_property (me, "vec-for-int", i*2, &portval_sc) || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1, &vec_sc) || portval_sc < 0 || vec_sc < 0) hw_abort (me, "no valid vector translation pair %u", i); crishw->int_to_vec[i].portval = (unsigned32) portval_sc; crishw->int_to_vec[i].vec = (unsigned32) vec_sc; } crishw->int_to_vec[i].portval = 0; crishw->int_to_vec[i].vec = 0; } multiple_int = hw_find_property (me, "multiple-int"); if (multiple_int != NULL) { if (hw_property_type (multiple_int) == integer_property) { crishw->multiple_int_vector = hw_find_integer_property (me, "multiple-int"); crishw->multi_int_action = cris_multint_vector; } else { const char *action = hw_find_string_property (me, "multiple-int"); if (action == NULL) hw_abort (me, "property \"multiple-int\" has the wrong type"); if (strcmp (action, "abort") == 0) crishw->multi_int_action = cris_multint_abort; else if (strcmp (action, "ignore_previous") == 0) crishw->multi_int_action = cris_multint_ignore_previous; else hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n" "\"abort\" and \"ignore_previous\", not \"%s\"", action); } } else crishw->multi_int_action = cris_multint_abort; }
static void attach_nvram_regs (struct hw *me, struct nvram *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; int result, oerrno; /* Get ram bank description (base and size). */ if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); controller->mode = NVRAM_SAVE_ALL; controller->base_address = attach_address; controller->size = attach_size; controller->fd = -1; /* Get the file where the ram content must be loaded/saved. */ if(hw_find_property (me, "file") == NULL) hw_abort (me, "Missing \"file\" property"); controller->file_name = hw_find_string_property (me, "file"); /* Get the mode which defines how to save the memory. */ if(hw_find_property (me, "mode") != NULL) { const char *value = hw_find_string_property (me, "mode"); if (strcmp (value, "map") == 0) controller->mode = NVRAM_MAP_FILE; else if (strcmp (value, "save-modified") == 0) controller->mode = NVRAM_SAVE_MODIFIED; else if (strcmp (value, "save-all") == 0) controller->mode = NVRAM_SAVE_ALL; else hw_abort (me, "illegal value for mode parameter `%s': " "use map, save-modified or save-all", value); } /* Initialize the ram by loading/mapping the file in memory. If the file does not exist, create and give it some content. */ switch (controller->mode) { case NVRAM_MAP_FILE: hw_abort (me, "'map' mode is not yet implemented, use 'save-modified'"); break; case NVRAM_SAVE_MODIFIED: case NVRAM_SAVE_ALL: controller->data = (char*) hw_malloc (me, attach_size); if (controller->data == 0) hw_abort (me, "Not enough memory, try to use the mode 'map'"); memset (controller->data, 0, attach_size); controller->fd = open (controller->file_name, O_RDWR); if (controller->fd < 0) { controller->fd = open (controller->file_name, O_RDWR | O_CREAT, 0644); if (controller->fd < 0) hw_abort (me, "Cannot open or create file '%s'", controller->file_name); result = write (controller->fd, controller->data, attach_size); if (result != attach_size) { oerrno = errno; hw_free (me, controller->data); close (controller->fd); errno = oerrno; hw_abort (me, "Failed to save the ram content"); } } else { result = read (controller->fd, controller->data, attach_size); if (result != attach_size) { oerrno = errno; hw_free (me, controller->data); close (controller->fd); errno = oerrno; hw_abort (me, "Failed to load the ram content"); } } if (controller->mode == NVRAM_SAVE_ALL) { close (controller->fd); controller->fd = -1; } break; default: break; } }