static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id, int enable, int is_group) { struct intc_source *source = desc->sources + id; if (!id) return; if (!source->next_enum_id && (!source->enable_max || !source->vect)) { #ifdef DEBUG_INTC_SOURCES printf("sh_intc: reserved interrupt source %d modified\n", id); #endif return; } if (source->vect) sh_intc_toggle_source(source, enable ? 1 : -1, 0); #ifdef DEBUG_INTC else { printf("setting interrupt group %d to %d\n", id, !!enable); } #endif if ((is_group || !source->vect) && source->next_enum_id) { sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1); } #ifdef DEBUG_INTC if (!source->vect) { printf("setting interrupt group %d to %d - done\n", id, !!enable); } #endif }
static void sh_intc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { struct intc_desc *desc = opaque; intc_enum *enum_ids = NULL; unsigned int first = 0; unsigned int width = 0; unsigned int mode = 0; unsigned int k; unsigned long *valuep; unsigned long mask; #ifdef DEBUG_INTC printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value); #endif sh_intc_locate(desc, (unsigned long)offset, &valuep, &enum_ids, &first, &width, &mode); switch (mode) { case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break; case INTC_MODE_DUAL_SET: value |= *valuep; break; case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break; default: abort(); } for (k = 0; k <= first; k++) { mask = ((1 << width) - 1) << ((first - k) * width); if ((*valuep & mask) == (value & mask)) continue; #if 0 printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", k, first, enum_ids[k], (unsigned int)mask); #endif sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0); } *valuep = value; #ifdef DEBUG_INTC printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value); #endif }