diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/devices.h | 3 | ||||
-rw-r--r-- | hw/irq.c | 2 | ||||
-rw-r--r-- | hw/stellaris.c | 36 | ||||
-rw-r--r-- | hw/stellaris_input.c | 66 |
4 files changed, 101 insertions, 6 deletions
diff --git a/hw/devices.h b/hw/devices.h index 3827745653..07c673b77d 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -16,4 +16,7 @@ uint32_t ads7846_read(void *opaque); void ads7846_write(void *opaque, uint32_t value); struct ads7846_state_s *ads7846_init(qemu_irq penirq); +/* stellaris_input.c */ +void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); + #endif @@ -65,5 +65,7 @@ static void qemu_notirq(void *opaque, int line, int level) qemu_irq qemu_irq_invert(qemu_irq irq) { + /* The default state for IRQs is low, so raise the output now. */ + qemu_irq_raise(irq); return qemu_allocate_irqs(qemu_notirq, irq, 1)[0]; } diff --git a/hw/stellaris.c b/hw/stellaris.c index 878c7f84e5..3dbb2ced62 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -16,6 +16,18 @@ #include "sysemu.h" #include "boards.h" +#define GPIO_A 0 +#define GPIO_B 1 +#define GPIO_C 2 +#define GPIO_D 3 +#define GPIO_E 4 +#define GPIO_F 5 +#define GPIO_G 6 + +#define BP_OLED_I2C 0x01 +#define BP_OLED_SSI 0x02 +#define BP_GAMEPAD 0x04 + typedef const struct { const char *name; uint32_t did0; @@ -25,7 +37,7 @@ typedef const struct { uint32_t dc2; uint32_t dc3; uint32_t dc4; - enum {OLED_I2C, OLED_SSI} oled; + uint32_t peripherals; } stellaris_board_info; /* General purpose timer module. */ @@ -991,7 +1003,7 @@ static stellaris_board_info stellaris_boards[] = { 0x01071013, 0x3f0f01ff, 0x0000001f, - OLED_I2C + BP_OLED_I2C }, { "LM3S6965EVB", 0x10010002, @@ -1001,7 +1013,7 @@ static stellaris_board_info stellaris_boards[] = { 0x030f5317, 0x0f0f87ff, 0x5000007f, - OLED_SSI + BP_OLED_SSI | BP_GAMEPAD } }; @@ -1052,7 +1064,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 12)) { i2c = i2c_init_bus(); stellaris_i2c_init(0x40020000, pic[8], i2c); - if (board->oled == OLED_I2C) { + if (board->peripherals & BP_OLED_I2C) { ssd0303_init(ds, i2c, 0x3d); } } @@ -1064,15 +1076,27 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } } if (board->dc2 & (1 << 4)) { - if (board->oled == OLED_SSI) { + if (board->peripherals & BP_OLED_SSI) { void * oled; /* FIXME: Implement chip select for OLED/MMC. */ - oled = ssd0323_init(ds, &gpio_out[2][7]); + oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); pl022_init(0x40008000, pic[7], ssd0323_xfer_ssi, oled); } else { pl022_init(0x40008000, pic[7], NULL, NULL); } } + if (board->peripherals & BP_GAMEPAD) { + qemu_irq gpad_irq[5]; + static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; + + gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ + gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ + gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ + gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ + gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ + + stellaris_gamepad_init(5, gpad_irq, gpad_keycode); + } } /* FIXME: Figure out how to generate these from stellaris_boards. */ diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c new file mode 100644 index 0000000000..461868b2ee --- /dev/null +++ b/hw/stellaris_input.c @@ -0,0 +1,66 @@ +/* + * Gamepad style buttons connected to IRQ/GPIO lines + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ +#include "hw.h" +#include "devices.h" +#include "console.h" + +typedef struct { + qemu_irq irq; + int keycode; + int pressed; +} gamepad_button; + +typedef struct { + gamepad_button *buttons; + int num_buttons; + int extension; +} gamepad_state; + +static void stellaris_gamepad_put_key(void * opaque, int keycode) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + int down; + + if (keycode == 0xe0 && !s->extension) { + s->extension = 0x80; + return; + } + + down = (keycode & 0x80) == 0; + keycode = (keycode & 0x7f) | s->extension; + + for (i = 0; i < s->num_buttons; i++) { + if (s->buttons[i].keycode == keycode + && s->buttons[i].pressed != down) { + s->buttons[i].pressed = down; + qemu_set_irq(s->buttons[i].irq, down); + } + } + + s->extension = 0; +} + +/* Returns an array 5 ouput slots. */ +void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) +{ + gamepad_state *s; + int i; + + s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state)); + s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button)); + for (i = 0; i < n; i++) { + s->buttons[i].irq = irq[i]; + s->buttons[i].keycode = keycode[i]; + } + s->num_buttons = n; + qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); +} + + |