added IKBD queue code

This commit is contained in:
Markus Fröschle
2013-12-11 05:11:06 +00:00
parent 524c94d465
commit c4a2a5f912
4 changed files with 385 additions and 0 deletions

View File

@@ -90,6 +90,8 @@ CSRCS= \
$(SRCDIR)/ohci-hcd.c \ $(SRCDIR)/ohci-hcd.c \
$(SRCDIR)/ehci-hcd.c \ $(SRCDIR)/ehci-hcd.c \
\ \
$(SRCDIR)/ikbd.c \
\
$(SRCDIR)/basflash.c \ $(SRCDIR)/basflash.c \
$(SRCDIR)/basflash_start.c $(SRCDIR)/basflash_start.c

11
include/ikbd.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _IKBD_H_
#define _IKBD_H_
extern void ikbd_init(void);
extern void ikbd_poll(void);
extern void ikbd_joystick(uint8_t joy, uint8_t map);
extern void ikbd_mouse(uint8_t buttons, int8_t x, int8_t y);
extern void ikbd_keyboard(uint8_t code);
#endif /* _IKBD_H_ */

57
include/user_io.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* user_io.h
*
*/
#ifndef _USER_IO_H_
#define _USER_IO_H_
#define UIO_STATUS 0x00
#define UIO_BUT_SW 0x01
// codes as used by minimig (amiga)
#define UIO_JOYSTICK0 0x02
#define UIO_JOYSTICK1 0x03
#define UIO_MOUSE 0x04
#define UIO_KEYBOARD 0x05
#define UIO_KBD_OSD 0x06 // keycodes used by OSD only
// codes as used by MiST (atari)
#define UIO_IKBD_OUT 0x02
#define UIO_IKBD_IN 0x03
#define UIO_SERIAL_OUT 0x04
#define UIO_SERIAL_IN 0x05
#define JOY_RIGHT 0x01
#define JOY_LEFT 0x02
#define JOY_DOWN 0x04
#define JOY_UP 0x08
#define JOY_BTN1 0x10
#define JOY_BTN2 0x20
#define JOY_MOVE (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
#define BUTTON1 0x01
#define BUTTON2 0x02
#define SWITCH1 0x04
#define SWITCH2 0x08
// core type value should be unlikely to be returned by broken cores
#define CORE_TYPE_UNKNOWN 0x55
#define CORE_TYPE_DUMB 0xa0
#define CORE_TYPE_MINIMIG 0xa1
#define CORE_TYPE_PACE 0xa2
#define CORE_TYPE_MIST 0xa3
void user_io_init();
void user_io_detect_core_type();
unsigned char user_io_core_type();
void user_io_poll();
int user_io_button_pressed();
void user_io_osd_key_enable(char);
// hooks from the usb layer
void user_io_mouse(unsigned char b, char x, char y);
void user_io_kbd(unsigned char m, unsigned char *k);
#endif /* _USER_IO_H_ */

315
sources/ikbd.c Normal file
View File

@@ -0,0 +1,315 @@
/*
https://www.kernel.org/doc/Documentation/input/atarikbd.txt
ikbd ToDo:
Feature Example using/needing it impl. tested
---------------------------------------------------------------------
mouse y at bottom Bolo X X
mouse button key events Goldrunner/A_008 X X
joystick interrogation mode Xevious/A_004 X X
Absolute mouse mode Backlash/A_008, A-Ball/A50
disable mouse ? X
disable joystick ? X
Joysticks also generate Goldrunner X X
mouse button events!
Pause (cmd 0x13) Wings of Death/A_427
*/
#include <stdint.h>
#include "bas_printf.h"
#include "bas_string.h"
#include "user_io.h"
//#include "hardware.h"
#include "ikbd.h"
// atari ikbd stuff
#define IKBD_STATE_JOYSTICK_EVENT_REPORTING 0x01
#define IKBD_STATE_MOUSE_Y_BOTTOM 0x02
#define IKBD_STATE_MOUSE_BUTTON_AS_KEY 0x04 // mouse buttons act like keys
#define IKBD_STATE_MOUSE_DISABLED 0x08
#define IKBD_STATE_MOUSE_ABSOLUTE 0x10
#define IKBD_DEFAULT IKBD_STATE_JOYSTICK_EVENT_REPORTING
#define QUEUE_LEN 16 // power of 2!
static unsigned char tx_queue[QUEUE_LEN];
static unsigned char wptr = 0, rptr = 0;
// structure to keep track of ikbd state
static struct {
unsigned char cmd;
unsigned char state;
unsigned char expect;
// joystick state
unsigned char joystick[2];
// mouse state
unsigned short mouse_pos_x, mouse_pos_y;
unsigned char mouse_buttons;
} ikbd;
// #define IKBD_DEBUG
void ikbd_init() {
// reset ikbd state
memset(&ikbd, 0, sizeof(ikbd));
ikbd.state = IKBD_DEFAULT;
}
static void enqueue(unsigned char b) {
if(((wptr + 1)&(QUEUE_LEN-1)) == rptr) {
xprintf("IKBD: !!!!!!! tx queue overflow !!!!!!!!!\n");
return;
}
tx_queue[wptr] = b;
wptr = (wptr+1)&(QUEUE_LEN-1);
}
// convert internal joystick format into atari ikbd format
static unsigned char joystick_map2ikbd(unsigned in) {
unsigned char out = 0;
if(in & JOY_UP) out |= 0x01;
if(in & JOY_DOWN) out |= 0x02;
if(in & JOY_LEFT) out |= 0x04;
if(in & JOY_RIGHT) out |= 0x08;
if(in & JOY_BTN1) out |= 0x80;
return out;
}
// process inout from atari core into ikbd
void ikbd_handle_input(unsigned char cmd) {
// expecting a second byte for command
if(ikbd.expect) {
ikbd.expect--;
// last byte of command received
if(!ikbd.expect) {
switch(ikbd.cmd) {
case 0x07: // set mouse button action
xprintf("IKBD: mouse button action = %x\n", cmd);
// bit 2: Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
if(cmd & 0x04) ikbd.state |= IKBD_STATE_MOUSE_BUTTON_AS_KEY;
else ikbd.state &= ~IKBD_STATE_MOUSE_BUTTON_AS_KEY;
break;
case 0x80: // ibkd reset
// reply "everything is ok"
enqueue(0xf0);
break;
default:
break;
}
}
return;
}
ikbd.cmd = cmd;
switch(cmd) {
case 0x07:
xprintf("IKBD: Set mouse button action");
ikbd.expect = 1;
break;
case 0x08:
xprintf("IKBD: Set relative mouse positioning");
ikbd.state &= ~IKBD_STATE_MOUSE_DISABLED;
ikbd.state &= ~IKBD_STATE_MOUSE_ABSOLUTE;
break;
case 0x09:
xprintf("IKBD: Set absolute mouse positioning");
ikbd.state &= ~IKBD_STATE_MOUSE_DISABLED;
ikbd.state |= IKBD_STATE_MOUSE_ABSOLUTE;
ikbd.expect = 4;
break;
case 0x0b:
xprintf("IKBD: Set Mouse threshold");
ikbd.expect = 2;
break;
case 0x0f:
xprintf("IKBD: Set Y at bottom");
ikbd.state |= IKBD_STATE_MOUSE_Y_BOTTOM;
break;
case 0x10:
xprintf("IKBD: Set Y at top");
ikbd.state &= ~IKBD_STATE_MOUSE_Y_BOTTOM;
break;
case 0x12:
xprintf("IKBD: Disable mouse");
ikbd.state |= IKBD_STATE_MOUSE_DISABLED;
break;
case 0x14:
xprintf("IKBD: Set Joystick event reporting");
ikbd.state |= IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x15:
xprintf("IKBD: Set Joystick interrogation mode");
ikbd.state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x16: // interrogate joystick
// send reply
enqueue(0xfd);
enqueue(joystick_map2ikbd(ikbd.joystick[0]));
enqueue(joystick_map2ikbd(ikbd.joystick[1]));
break;
case 0x1a:
xprintf("IKBD: Disable joysticks");
ikbd.state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x1c:
xprintf("IKBD: Interrogate time of day");
enqueue(0xfc);
enqueue(0x13); // year bcd
enqueue(0x03); // month bcd
enqueue(0x07); // day bcd
enqueue(0x20); // hour bcd
enqueue(0x58); // minute bcd
enqueue(0x00); // second bcd
break;
case 0x80:
xprintf("IKBD: Reset");
ikbd.expect = 1;
ikbd.state = IKBD_DEFAULT;
break;
default:
xprintf("IKBD: unknown command: %x\n", cmd);
break;
}
}
void ikbd_poll(void) {
static mtimer = 0;
if(CheckTimer(mtimer)) {
mtimer = GetTimer(10);
// check for incoming ikbd data
EnableIO();
SPI(UIO_IKBD_IN);
while(SPI(0))
ikbd_handle_input(SPI(0));
DisableIO();
}
// send data from queue if present
if(rptr == wptr) return;
// transmit data from queue
EnableIO();
SPI(UIO_IKBD_OUT);
SPI(tx_queue[rptr]);
DisableIO();
rptr = (rptr+1)&(QUEUE_LEN-1);
}
void ikbd_joystick(unsigned char joystick, unsigned char map) {
// todo: suppress events for joystick 0 as long as mouse
// is enabled?
if(ikbd.state & IKBD_STATE_JOYSTICK_EVENT_REPORTING) {
#ifdef IKBD_DEBUG
xprintf("IKBD: joy %d %x\n", joystick, map);
#endif
// only report joystick data for joystick 0 if the mouse is disabled
if((ikbd.state & IKBD_STATE_MOUSE_DISABLED) || (joystick == 1)) {
enqueue(0xfe + joystick);
enqueue(joystick_map2ikbd(map));
}
if(!(ikbd.state & IKBD_STATE_MOUSE_DISABLED)) {
// the fire button also generates a mouse event if
// mouse reporting is enabled
if((map & JOY_BTN1) != (ikbd.joystick[joystick] & JOY_BTN1)) {
// generate mouse event (ikbd_joystick_buttons is evaluated inside
// user_io_mouse)
ikbd.joystick[joystick] = map;
ikbd_mouse(0, 0, 0);
}
}
}
#ifdef IKBD_DEBUG
else
xprintf("IKBD: no monitor, drop joy %d %x\n", joystick, map);
#endif
// save state of joystick for interrogation mode
ikbd.joystick[joystick] = map;
}
void ikbd_keyboard(unsigned char code) {
#ifdef IKBD_DEBUG
xprintf("IKBD: send keycode %x%s\n", code&0x7f, (code&0x80)?" BREAK":"");
#endif
enqueue(code);
}
void ikbd_mouse(uint8_t b, int8_t x, int8_t y) {
if(ikbd.state & IKBD_STATE_MOUSE_DISABLED)
return;
// joystick and mouse buttons are wired together in
// atari st
b |= (ikbd.joystick[0] & JOY_BTN1)?1:0;
b |= (ikbd.joystick[1] & JOY_BTN1)?2:0;
static unsigned char b_old = 0;
// monitor state of two mouse buttons
if(b != b_old) {
// check if mouse buttons are supposed to be treated like keys
if(ikbd.state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
// Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
// handle left mouse button
if((b ^ b_old) & 1) ikbd_keyboard(0x74 | ((b&1)?0x00:0x80));
// handle right mouse button
if((b ^ b_old) & 2) ikbd_keyboard(0x75 | ((b&2)?0x00:0x80));
}
b_old = b;
}
#if 0
if(ikbd.state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
b = 0;
// if mouse position is 0/0 quit here
if(!x && !y) return;
}
#endif
if(ikbd.state & IKBD_STATE_MOUSE_ABSOLUTE) {
} else {
// atari has mouse button bits swapped
enqueue(0xf8|((b&1)?2:0)|((b&2)?1:0));
enqueue(x);
enqueue((ikbd.state & IKBD_STATE_MOUSE_Y_BOTTOM)?-y:y);
}
}