diff --git a/Makefile b/Makefile index 82e42028726b7bed56a22cc7a8bf77be5a0f1142..493330c092272e7df252e4cdffc5024a4a058782 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ OBJS+=block.o OBJS+=irq.o OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o -OBJS+=ssd0303.o ssd0323.o ads7846.o +OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o OBJS+=scsi-disk.o cdrom.o OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o diff --git a/hw/devices.h b/hw/devices.h index 382774565375b9f8384105cab07ebbf38e795da6..07c673b77d3fc901994d071cf93a30cacd7e1804 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 diff --git a/hw/irq.c b/hw/irq.c index 960155ad04749bcafd97ad72bd1ae7db9737adab..eca707dd06e2c8e6e1031b39738b3ea5c4ee3f42 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -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 878c7f84e58971e5b1fd0a2be37eb22744c1f113..3dbb2ced6214423285e33dfa0429ac7997b9bb76 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 0000000000000000000000000000000000000000..461868b2eefad2e49ec8f349925b964b74537eec --- /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); +} + +