x49gp/s3c2410_intc.c
claudiol c61f11cff2 On behalf of: 3298 - Applied 23 patches by 3298:
Misc changes, mostly fixes:
- fix ./newconfig systems other than OSX (broke in c8b823f)
- fix palette usage in 2-bit color mode (was broken ever since grayscale was implemented in 18e1003 and its improperly attributed copy f7913eb)
- fix continuing from breakpoints in the debugger (never worked, was exposed when the debugger was enabled in 9c1f2ed)
- restore the printf statements commented out in 9c1f2ed and hide them with #ifdefs instead
- close the server socket after accepting a debugger connection to allow another simultaneous debug session to be started using the same TCP port
- use the symbolic constant DEFAULT_GDBSTUB_PORT (already defined in gdb_stub.h as 1234) when starting the gdb server in main.c in place of the raw number 1234
- change Makefile to read the name of the firmware file from the file update.scp instead of hardcoding it; this allows users to switch to another firmware
by simply pasting it along with its accompanying update.scp into the x49gp directory

- Enhance port G (keyboard) handling to remember the value of output bits across periods with these bits configured as input
This fixes interaction with HPGCC3 keyboard routines, and it also fixes keys with eint==7 (assuming the stock firmware is in use)
needing a double-tap to work unless pressed very shortly after another keypress (the latter broke in b5f93ed)
- Get rid of the deprecated function warning by switching from gdk_pixbuf_new_from_inline to gdk_pixbuf_new_from_data (based on code by chwdt)
- Delete remaining now-redundant CVS files
- Don't release all buttons anymore if there are still physical keys and/or the left mouse button are holding some down
On the other hand, forcibly release all buttons when losing focus to avoid getting stuck in a state with buttons down
when they are not held down by anything; this would happen due to missed events while not in focus
- Add a context menu to the screen, containing only "Reset" and "Quit" items for now
- Ensure that the files backing flash, sram, and s3c2410-sram exist and have the correct size when opening them
Note that if the flash file does not exist, this will not fill it with the code that's supposed to be in there, obviously causing the calculator to crash. That's an improvement for later.
- Allow the config system to fill not only numbers, but also strings (including filenames) with default values
basename is excluded, but it's planned to be dropped entirely.
- Add an "install" target to the Makefile
- Implement a more generic command-line parser for substantially improved flexibility
- Also adds a proper help option, though the manual referenced in the corresponding output (a manpage, hopefully) does not exist yet.
- Drop the "basename" config property in favor of interpreting relative paths in the config as relative to the config file's location
- Retire the "image" config property in favor of simply loading the image from next to the binary or from the install directory
- Split the UI name property into name (affecting only the window title) and type (affecting the UI image and in the future also the default bootcode) properties
- Change the default calculator type to the 50g everywhere, which probably matches today's user expectations better than the 49g+.
- Create a flash file from the calculator model's appropriate boot file if it does not exist, relying on the bootcode to detect the absence of a firmware
  The bootcode will complain about the missing firmware and enter update mode, so the user needs to supply their favorite firmware version and point the bootcode's updater to it.
  The easiest way is probably pointing the emulated SD card at a directory containing the firmware and its accompanying update.scp file, and then starting the SD-based update.
- Add SD mount / unmount options to the right-click / menu-key popup menu
- Remove most of the old script-based config-generating system since the binary now has these capabilities as well
- Add an applications menu item for installing
- Keep some debug output on stderr and a huge vvfat.log file from showing up when not debugging x49gp itself
- Allow (re-)connecting a debugger to a running session
  This is done through the right-click / menu-key popup menu.
  To avoid confusion due to the accidental clicks leading to an unresponsive interface (caused by waiting for the debugger to connect),
  this option is hidden unless option -d or its new companion -D (same as -d, but does not start the debug interface right away) is present.
- Improved support for hardware keyboards
- Update README.md, add manpage, rename other README files to TODO to reflect their contents
2018-05-07 17:32:14 -04:00

755 lines
15 KiB
C

/* $Id: s3c2410_intc.c,v 1.8 2008/12/11 12:18:17 ecd Exp $
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <x49gp.h>
#include <s3c2410.h>
#include <s3c2410_intc.h>
#include <s3c2410_power.h>
#include <byteorder.h>
extern int do_trace;
typedef struct {
int sel_shift;
uint32_t mode_bit;
int index;
int req[6];
} s3c2410_arb_t;
typedef struct {
uint32_t sel;
uint32_t mode;
} s3c2410_arb_data_t;
static const int s3c2410_arb_order[4][6] =
{
{ 0, 1, 2, 3, 4, 5 },
{ 0, 2, 3, 4, 1, 5 },
{ 0, 3, 4, 1, 2, 5 },
{ 0, 4, 1, 2, 3, 5 }
};
static const s3c2410_arb_t s3c2410_arb_table[] =
{
[0] = { ARB0_SEL_SHIFT, ARB0_MODE, 0,
{ -1, EINT0, EINT1, EINT2, EINT3, -1 } },
[1] = { ARB1_SEL_SHIFT, ARB1_MODE, 1,
{ EINT4_7, EINT8_23, -1, nBATT_FLT, INT_TICK, INT_WDT } },
[2] = { ARB2_SEL_SHIFT, ARB2_MODE, 2,
{ INT_TIMER0, INT_TIMER1, INT_TIMER2, INT_TIMER3, INT_TIMER4, INT_UART2} },
[3] = { ARB3_SEL_SHIFT, ARB3_MODE, 3,
{ INT_LCD, INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3, INT_SDI } },
[4] = { ARB4_SEL_SHIFT, ARB4_MODE, 4,
{ INT_SPI0, INT_UART1, -1, INT_USBD, INT_USBH, INT_IIC } },
[5] = { ARB5_SEL_SHIFT, ARB5_MODE, 5,
{ -1, INT_UART0, INT_SPI1, INT_RTC, INT_ADC, -1, } },
[6] = { ARB6_SEL_SHIFT, ARB6_MODE, 6,
{ 0, 1, 2, 3, 4, 5 } },
};
#define INTC_NR_ARB (sizeof(s3c2410_arb_table) / sizeof(s3c2410_arb_table[0]))
typedef struct {
uint32_t srcpnd;
uint32_t intmod;
uint32_t intmsk;
uint32_t priority;
uint32_t intpnd;
uint32_t intoffset;
uint32_t subsrcpnd;
uint32_t intsubmsk;
s3c2410_arb_data_t arb_data[INTC_NR_ARB];
x49gp_t *x49gp;
uint32_t src_pending;
uint32_t subsrc_pending;
unsigned int nr_regs;
s3c2410_offset_t *regs;
} s3c2410_intc_t;
static void s3c2410_intc_gen_int(s3c2410_intc_t *intc);
static void s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc);
static int
s3c2410_intc_data_init(s3c2410_intc_t *intc)
{
int i;
s3c2410_offset_t regs[] = {
S3C2410_OFFSET(INTC, SRCPND, 0x00000000, intc->srcpnd),
S3C2410_OFFSET(INTC, INTMOD, 0x00000000, intc->intmod),
S3C2410_OFFSET(INTC, INTMSK, 0xffffffff, intc->intmsk),
S3C2410_OFFSET(INTC, PRIORITY, 0x0000007f, intc->priority),
S3C2410_OFFSET(INTC, INTPND, 0x00000000, intc->intpnd),
S3C2410_OFFSET(INTC, INTOFFSET, 0x00000000, intc->intoffset),
S3C2410_OFFSET(INTC, SUBSRCPND, 0x00000000, intc->subsrcpnd),
S3C2410_OFFSET(INTC, INTSUBMSK, 0x000007ff, intc->intsubmsk)
};
memset(intc, 0, sizeof(s3c2410_intc_t));
intc->regs = malloc(sizeof(regs));
if (NULL == intc->regs) {
fprintf(stderr, "%s:%u: Out of memory\n",
__FUNCTION__, __LINE__);
return -ENOMEM;
}
memcpy(intc->regs, regs, sizeof(regs));
intc->nr_regs = sizeof(regs) / sizeof(regs[0]);
for (i = 0; i < INTC_NR_ARB; i++) {
intc->arb_data[i].sel = 0;
intc->arb_data[i].mode = s3c2410_arb_table[i].mode_bit;
}
return 0;
}
static void
srcpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
{
intc->srcpnd &= ~(data);
intc->srcpnd |= intc->src_pending;
if (intc->src_pending & data) {
s3c2410_intc_gen_int(intc);
}
}
static void
intmod_put_word(s3c2410_intc_t *intc, uint32_t data)
{
intc->intmod = data & 0xfeffffbf;
s3c2410_intc_gen_int(intc);
}
static void
intmsk_put_word(s3c2410_intc_t *intc, uint32_t data)
{
#ifdef DEBUG_X49GP_ENABLE_IRQ
uint32_t change;
int i;
change = intc->intmsk ^ data;
#endif
intc->intmsk = data | 0x01000040;
#ifdef DEBUG_X49GP_ENABLE_IRQ
for (i = 0; i < 32; i++) {
if ((change & (1 << i)) && !(intc->intmsk & (1 << i))) {
printf("INTC: Enable IRQ %u\n", i);
}
}
#endif
s3c2410_intc_gen_int(intc);
}
static uint32_t
priority_get_word(s3c2410_intc_t *intc)
{
const s3c2410_arb_t *arb;
s3c2410_arb_data_t *arb_data;
int i;
intc->priority = 0;
for (i = 0; i < INTC_NR_ARB; i++) {
arb = &s3c2410_arb_table[i];
arb_data = &intc->arb_data[i];
intc->priority |= (arb_data->sel << arb->sel_shift) |
arb_data->mode;
}
return intc->priority;
}
static void
priority_put_word(s3c2410_intc_t *intc, uint32_t data)
{
const s3c2410_arb_t *arb;
s3c2410_arb_data_t *arb_data;
int i;
intc->priority = data & 0x001fffff;
for (i = 0; i < INTC_NR_ARB; i++) {
arb = &s3c2410_arb_table[i];
arb_data = &intc->arb_data[i];
arb_data->sel = (intc->priority >> arb->sel_shift) & ARBx_SEL_MASK;
arb_data->mode = intc->priority & arb->mode_bit;
}
s3c2410_intc_gen_int(intc);
}
static void
intpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
{
intc->intpnd &= ~(data);
s3c2410_intc_gen_int(intc);
}
static void
subsrcpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
{
intc->subsrcpnd &= ~(data);
intc->subsrcpnd |= intc->subsrc_pending;
if (intc->subsrc_pending & data) {
s3c2410_intc_gen_int_from_sub_int(intc);
}
}
static void
intsubmsk_put_word(s3c2410_intc_t *intc, uint32_t data)
{
intc->intsubmsk = data & 0x000007ff;
s3c2410_intc_gen_int_from_sub_int(intc);
}
static uint32_t
s3c2410_intc_select_int(s3c2410_intc_t *intc, const s3c2410_arb_t *arb,
uint32_t service, int *offset)
{
s3c2410_arb_data_t *arb_data = &intc->arb_data[arb->index];
const int *order;
int i, req;
order = s3c2410_arb_order[arb_data->sel];
for (i = 0; i < 6; i++) {
req = order[i];
if (-1 == arb->req[req])
continue;
if (service & (1 << arb->req[req])) {
if (arb_data->mode)
arb_data->sel = (arb_data->sel + 1) & ARBx_SEL_MASK;
*offset = arb->req[req];
return (1 << arb->index);
}
}
*offset = -1;
return 0;
}
void
s3c2410_FIQ (CPUState *env)
{
cpu_interrupt(env, CPU_INTERRUPT_FIQ);
}
void
s3c2410_IRQ (CPUState *env)
{
cpu_interrupt(env, CPU_INTERRUPT_HARD);
}
static void
s3c2410_intc_gen_int(s3c2410_intc_t *intc)
{
x49gp_t *x49gp = intc->x49gp;
uint32_t fiq, service;
int offset[6], index;
const s3c2410_arb_t *arb;
uint32_t request;
int i;
fiq = intc->srcpnd & intc->intmod;
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: FIQ service request: %08x\n", fiq);
#endif
if (fiq) {
/*
* Generate FIQ.
*/
#ifdef DEBUG_S3C2410_INTC
printf("INTC: vector to %08x\n", 0x1c);
#endif
cpu_interrupt(x49gp->env, CPU_INTERRUPT_FIQ);
x49gp_set_idle(x49gp, 0);
return;
} else {
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_FIQ);
}
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: IRQ pending request: %08x\n", intc->intpnd);
#endif
if (intc->intpnd) {
/*
* Generate IRQ.
*/
#ifdef DEBUG_S3C2410_INTC
printf("INTC: vector to %08x\n", 0x18);
#endif
cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
x49gp_set_idle(x49gp, 0);
return;
}
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: srcpnd %08x, intmsk: %08x\n", intc->srcpnd, intc->intmsk);
#endif
service = intc->srcpnd & ~(intc->intmsk);
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: IRQ service request: %08x\n", service);
#endif
if (0 == service) {
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
return;
}
request = 0;
for (i = 0; i < 6; i++) {
arb = &s3c2410_arb_table[i];
request |= s3c2410_intc_select_int(intc, arb, service, &offset[i]);
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: ARB%u highest %d\n", i, offset[i]);
#endif
}
arb = &s3c2410_arb_table[6];
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: ARB%u request: %08x\n", 6, request);
#endif
if (s3c2410_intc_select_int(intc, arb, request, &index)) {
intc->intoffset = offset[index];
intc->intpnd |= (1 << intc->intoffset);
#ifdef DEBUG_S3C2410_INTC
printf("INTC: irq pending: %u (%08x)\n", intc->intoffset, intc->intpnd);
#endif
/*
* Generate IRQ.
*/
#ifdef DEBUG_S3C2410_INTC
printf("INTC: vector to %08x\n", 0x18);
#endif
cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
x49gp_set_idle(x49gp, 0);
return;
}
#ifdef DEBUG_S3C2410_INTC0
printf("INTC: No irq pending\n");
#endif
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
}
void
s3c2410_intc_assert(x49gp_t *x49gp, int irq, int level)
{
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
if (irq > 31)
return;
#ifdef DEBUG_S3C2410_INTC
printf("INTC: assert irq %u (%08x)\n", irq, 1 << irq);
#endif
if (! (intc->src_pending & (1 << irq))) {
if (level)
intc->src_pending |= (1 << irq);
intc->srcpnd |= (1 << irq);
s3c2410_intc_gen_int(intc);
}
if (x49gp->arm_idle == 2) {
if (irq == EINT0 || irq == INT_RTC)
x49gp_set_idle(x49gp, 0);
}
}
void
s3c2410_intc_deassert(x49gp_t *x49gp, int irq)
{
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
if (irq > 31)
return;
#ifdef DEBUG_S3C2410_INTC
printf("INTC: deassert irq %u (%08x)\n", irq, 1 << irq);
#endif
intc->src_pending &= ~(1 << irq);
}
static void
s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc)
{
x49gp_t *x49gp = intc->x49gp;
uint32_t service;
service = intc->subsrcpnd & ~(intc->intsubmsk);
#ifdef DEBUG_S3C2410_INTC
printf("INTC: subirq service request: %08x\n", service);
#endif
if (service & ((1 << SUB_INT_ERR0) | (1 << SUB_INT_TXD0) | (1 << SUB_INT_RXD0))) {
s3c2410_intc_assert(x49gp, INT_UART0, 1);
} else {
s3c2410_intc_deassert(x49gp, INT_UART0);
}
if (service & ((1 << SUB_INT_ERR1) | (1 << SUB_INT_TXD1) | (1 << SUB_INT_RXD1))) {
s3c2410_intc_assert(x49gp, INT_UART1, 1);
} else {
s3c2410_intc_deassert(x49gp, INT_UART1);
}
if (service & ((1 << SUB_INT_ERR2) | (1 << SUB_INT_TXD2) | (1 << SUB_INT_RXD2))) {
s3c2410_intc_assert(x49gp, INT_UART2, 1);
} else {
s3c2410_intc_deassert(x49gp, INT_UART2);
}
if (service & ((1 << SUB_INT_ADC) | (1 << SUB_INT_TC))) {
s3c2410_intc_assert(x49gp, INT_ADC, 1);
} else {
s3c2410_intc_deassert(x49gp, INT_ADC);
}
intc->subsrcpnd = intc->subsrc_pending;
}
void
s3c2410_intc_sub_assert(x49gp_t *x49gp, int sub_irq, int level)
{
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
if (sub_irq > 31)
return;
#ifdef DEBUG_S3C2410_INTC
printf("INTC: assert subirq %u (%08x)\n", sub_irq, 1 << sub_irq);
#endif
if (! (intc->subsrc_pending & (1 << sub_irq))) {
if (level)
intc->subsrc_pending |= (1 << sub_irq);
intc->subsrcpnd |= (1 << sub_irq);
s3c2410_intc_gen_int_from_sub_int(intc);
}
}
void
s3c2410_intc_sub_deassert(x49gp_t *x49gp, int sub_irq)
{
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
if (sub_irq > 31)
return;
#ifdef DEBUG_S3C2410_INTC
printf("INTC: deassert subirq %u (%08x)\n", sub_irq, 1 << sub_irq);
#endif
intc->subsrc_pending &= ~(1 << sub_irq);
}
static uint32_t
s3c2410_intc_read(void *opaque, target_phys_addr_t offset)
{
s3c2410_intc_t *intc = opaque;
s3c2410_offset_t *reg;
uint32_t data;
#ifdef QEMU_OLD
offset -= S3C2410_INTC_BASE;
#endif
if (! S3C2410_OFFSET_OK(intc, offset)) {
return ~(0);
}
reg = S3C2410_OFFSET_ENTRY(intc, offset);
switch (offset) {
case S3C2410_INTC_PRIORITY:
data = priority_get_word(intc);
break;
default:
data = *(reg->datap);
break;
}
#ifdef DEBUG_S3C2410_INTC
printf("read %s [%08x] %s [%08lx] data %08x\n",
"s3c2410-intc", S3C2410_INTC_BASE,
reg->name, (unsigned long) offset, data);
#endif
return data;
}
static void
s3c2410_intc_write(void *opaque, target_phys_addr_t offset, uint32_t data)
{
#ifdef DEBUG_S3C2410_INTC
s3c2410_offset_t *reg;
#endif
s3c2410_intc_t *intc = opaque;
#ifdef QEMU_OLD
offset -= S3C2410_INTC_BASE;
#endif
if (! S3C2410_OFFSET_OK(intc, offset)) {
return;
}
#ifdef DEBUG_S3C2410_INTC
reg = S3C2410_OFFSET_ENTRY(intc, offset);
printf("write %s [%08x] %s [%08lx] data %08x\n",
"s3c2410-intc", S3C2410_INTC_BASE,
reg->name, (unsigned long) offset, data);
#endif
switch (offset) {
case S3C2410_INTC_SRCPND:
srcpnd_put_word(intc, data);
break;
case S3C2410_INTC_INTMOD:
intmod_put_word(intc, data);
break;
case S3C2410_INTC_INTMSK:
intmsk_put_word(intc, data);
break;
case S3C2410_INTC_PRIORITY:
priority_put_word(intc, data);
break;
case S3C2410_INTC_INTPND:
intpnd_put_word(intc, data);
break;
case S3C2410_INTC_SUBSRCPND:
subsrcpnd_put_word(intc, data);
break;
case S3C2410_INTC_INTSUBMSK:
intsubmsk_put_word(intc, data);
break;
default:
break;
}
}
static int
s3c2410_intc_load(x49gp_module_t *module, GKeyFile *key)
{
s3c2410_intc_t *intc = module->user_data;
s3c2410_offset_t *reg;
int error = 0;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
for (i = 0; i < intc->nr_regs; i++) {
reg = &intc->regs[i];
if (NULL == reg->name)
continue;
if (x49gp_module_get_u32(module, key, reg->name,
reg->reset, reg->datap))
error = -EAGAIN;
}
intc->src_pending = intc->srcpnd;
intc->subsrc_pending = intc->subsrcpnd;
intc->srcpnd = 0;
intc->subsrcpnd = 0;
priority_put_word(intc, intc->priority);
intsubmsk_put_word(intc, intc->intsubmsk);
intmsk_put_word(intc, intc->intmsk);
return error;
}
static int
s3c2410_intc_save(x49gp_module_t *module, GKeyFile *key)
{
s3c2410_intc_t *intc = module->user_data;
s3c2410_offset_t *reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
intc->srcpnd = intc->src_pending;
intc->subsrcpnd = intc->subsrc_pending;
for (i = 0; i < intc->nr_regs; i++) {
reg = &intc->regs[i];
if (NULL == reg->name)
continue;
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
}
return 0;
}
static int
s3c2410_intc_reset(x49gp_module_t *module, x49gp_reset_t reset)
{
s3c2410_intc_t *intc = module->user_data;
s3c2410_offset_t *reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
if (reset == X49GP_RESET_POWER_OFF) {
return 0;
}
for (i = 0; i < intc->nr_regs; i++) {
reg = &intc->regs[i];
if (NULL == reg->name)
continue;
*(reg->datap) = reg->reset;
}
return 0;
}
static CPUReadMemoryFunc *s3c2410_intc_readfn[] =
{
s3c2410_intc_read,
s3c2410_intc_read,
s3c2410_intc_read
};
static CPUWriteMemoryFunc *s3c2410_intc_writefn[] =
{
s3c2410_intc_write,
s3c2410_intc_write,
s3c2410_intc_write
};
static int
s3c2410_intc_init(x49gp_module_t *module)
{
s3c2410_intc_t *intc;
int iotype;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
intc = malloc(sizeof(s3c2410_intc_t));
if (NULL == intc) {
fprintf(stderr, "%s:%u: Out of memory\n",
__FUNCTION__, __LINE__);
return -ENOMEM;
}
if (s3c2410_intc_data_init(intc)) {
free(intc);
return -ENOMEM;
}
module->user_data = intc;
intc->x49gp = module->x49gp;
intc->x49gp->s3c2410_intc = intc;
#ifdef QEMU_OLD
iotype = cpu_register_io_memory(0, s3c2410_intc_readfn,
s3c2410_intc_writefn, intc);
#else
iotype = cpu_register_io_memory(s3c2410_intc_readfn,
s3c2410_intc_writefn, intc);
#endif
#ifdef DEBUG_S3C2410_INTC
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
#endif
cpu_register_physical_memory(S3C2410_INTC_BASE, S3C2410_MAP_SIZE, iotype);
return 0;
}
static int
s3c2410_intc_exit(x49gp_module_t *module)
{
s3c2410_intc_t *intc;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
if (module->user_data) {
intc = module->user_data;
if (intc->regs)
free(intc->regs);
free(intc);
}
x49gp_module_unregister(module);
free(module);
return 0;
}
int
x49gp_s3c2410_intc_init(x49gp_t *x49gp)
{
x49gp_module_t *module;
if (x49gp_module_init(x49gp, "s3c2410-intc",
s3c2410_intc_init,
s3c2410_intc_exit,
s3c2410_intc_reset,
s3c2410_intc_load,
s3c2410_intc_save,
NULL, &module)) {
return -1;
}
return x49gp_module_register(module);
}