gint_strcat/src/gint_7305.c

293 lines
6.9 KiB
C

#include <gint.h>
#include <7305.h>
extern void print_hex(unsigned int value, int x, int y);
extern void print_bin(unsigned char value, int x, int y);
//---
// Interrupt codes.
//---
#define IC_RTC_PRI 0xaa0
#define IC_KEYSC 0xbe0
//---
// Keyboard management.
//---
extern volatile unsigned char keyboard_state[10];
extern void keyboard_interrupt(void);
/*
kdelay()
Should sleep during a few milliseconds. Well...
This delay has a great influence on key detection. Here are a few
observations of what happens with common numbers of "nop" (without
overclock). Take care of the effect of overclock !
Column effects
May have something to do with register HIZCRB not being used here. When
many keys on the same column are pressed, other keys of the same column
may be triggered.
- Less Bad key detection.
- 8 Very few column effects. Most often, three keys may be pressed
simultaneously. However, [UP] has latencies and is globally not
detected.
- 12 Seems best. Every individual key is detected well. No column
effect observed before four keys.
- 16 Every single key is detected correctly. Pressing two keys on a
same column does not usually create a column effect. Three keys
almost always.
- More Does not improve single key detection, and increase column
effects. At 256 every single key press create a whole column
effect.
*/
static void kdelay(void)
{
#define r4(str) str str str str
__asm__
(
r4("nop\n\t")
r4("nop\n\t")
r4("nop\n\t")
);
#undef r4
}
/*
krow()
Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for
more details.
@arg row Row to check (0 <= row <= 9).
@return Bit-based representation of pressed keys in the checked row.
*/
static int krow(int row)
{
volatile unsigned short *injector1 = (unsigned short *)0xa4050116;
volatile unsigned char *data1 = (unsigned char *)0xa4050136;
volatile unsigned short *injector2 = (unsigned short *)0xa4050118;
volatile unsigned char *data2 = (unsigned char *)0xa4050138;
volatile unsigned short *detector = (unsigned short *)0xa405014c;
volatile unsigned char *keys = (unsigned char *)0xa405016c;
volatile unsigned char *key_register = (unsigned char *)0xa40501c6;
// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a;
unsigned short smask;
unsigned char cmask;
int result = 0;
if(row < 0 || row > 9) return 0;
// Additional configuration for SH7305.
*detector = 0xaaaa;
*key_register = 0xff;
*injector1 = (*injector1 & 0xf000) | 0x0555;
*injector2 = (*injector2 & 0xf000) | 0x0555;
*data1 |= 0x3f;
*data2 |= 0x3f;
kdelay();
if(row < 6)
{
smask = 0x0003 << (row * 2);
cmask = ~(1 << row);
*injector1 = ((*injector1 & 0xf000) | 0x0aaa) ^ smask;
*injector2 = (*injector2 & 0xf000) | 0x0aaa;
kdelay();
*data1 = (*data1 & 0xc0) | cmask;
*data2 |= 0x3f;
kdelay();
}
else
{
smask = 0x0003 << ((row - 6) * 2);
cmask = ~(1 << (row - 6));
*injector1 = (*injector1 & 0xf000) | 0x0aaa;
*injector2 = ((*injector2 & 0xf000) | 0x0aaa) ^ smask;
kdelay();
*data1 |= 0x3f;
*data2 = (*data2 & 0xc0) | cmask;
kdelay();
}
// Reading the keyboard row.
result = ~*keys;
kdelay();
// Re-initializing the port configuration and data.
*injector1 = (*injector1 & 0xf000) | 0x0aaa;
*injector2 = (*injector2 & 0xf000) | 0x0aaa;
kdelay();
*injector1 = (*injector1 & 0xf000) | 0x0555;
*injector2 = (*injector2 & 0xf000) | 0x0555;
kdelay();
*data1 &= 0xc0;
*data2 &= 0xc0;
return result;
}
/*
kstate()
Updates the keyboard state.
*/
static void kstate(void)
{
int i;
for(i = 0; i < 10; i++) keyboard_state[i] = krow(i);
keyboard_interrupt();
}
//---
// Interrupt handler.
//---
void gint_7305(void)
{
volatile unsigned int *intevt = (unsigned int *)0xff000028;
unsigned int code = *intevt;
switch(code)
{
case IC_RTC_PRI:
// Clearing the interrupt flag.
RTC.RCR2.PEF = 0;
// Updating the keyboard state.
kstate();
/*
print_bin(keyboard_state[0], 0, 2);
print_bin(keyboard_state[1], 0, 3);
print_bin(keyboard_state[2], 0, 4);
print_bin(keyboard_state[3], 0, 5);
print_bin(keyboard_state[4], 0, 6);
print_bin(keyboard_state[5], 9, 2);
print_bin(keyboard_state[6], 9, 3);
print_bin(keyboard_state[7], 9, 4);
print_bin(keyboard_state[8], 9, 5);
print_bin(keyboard_state[9], 9, 6);
*/
break;
}
}
//---
// Setup.
//---
static unsigned short ipr[12];
static unsigned char rcr2;
// Saves of the keyboard registres. Could be better.
static unsigned short inj1, inj2, det;
static unsigned char data1, data2, keys, reg;
static void gint_priority_lock_7305(void)
{
// Saving the current interrupt priorities.
ipr[0] = INTX.IPRA.WORD;
ipr[1] = INTX.IPRB.WORD;
ipr[2] = INTX.IPRC.WORD;
ipr[3] = INTX.IPRD.WORD;
ipr[4] = INTX.IPRE.WORD;
ipr[5] = INTX.IPRF.WORD;
ipr[6] = INTX.IPRG.WORD;
ipr[7] = INTX.IPRH.WORD;
ipr[8] = INTX.IPRI.WORD;
ipr[9] = INTX.IPRJ.WORD;
ipr[10] = INTX.IPRK.WORD;
ipr[11] = INTX.IPRL.WORD;
// Disabling everything by default to avoid freezing on unhandled
// interrupts.
INTX.IPRA.WORD = 0x0000;
INTX.IPRB.WORD = 0x0000;
INTX.IPRC.WORD = 0x0000;
INTX.IPRD.WORD = 0x0000;
INTX.IPRE.WORD = 0x0000;
INTX.IPRF.WORD = 0x0000;
INTX.IPRG.WORD = 0x0000;
INTX.IPRH.WORD = 0x0000;
INTX.IPRI.WORD = 0x0000;
INTX.IPRJ.WORD = 0x0000;
INTX.IPRK.WORD = 0x0000;
INTX.IPRL.WORD = 0x0000;
// Saving keyboard registers.
inj1 = *((volatile unsigned short *)0xa4050116);
data1 = *((volatile unsigned char *)0xa4050136);
inj2 = *((volatile unsigned short *)0xa4050118);
data2 = *((volatile unsigned char *)0xa4050138);
det = *((volatile unsigned short *)0xa405014c);
keys = *((volatile unsigned char *)0xa405016c);
reg = *((volatile unsigned char *)0xa40501c6);
// Allowing RTC. Keyboard analysis is done regularly using a RTC
// because SH7305's special KEYSC interface does not allow us to clear
// the keyboard interrupt flags.
INTX.IPRK._RTC = GINT_INTP_RTC;
}
static void gint_priority_unlock_7305(void)
{
// Restoring the interrupt priorities.
INTX.IPRA.WORD = ipr[0];
INTX.IPRB.WORD = ipr[1];
INTX.IPRC.WORD = ipr[2];
INTX.IPRD.WORD = ipr[3];
INTX.IPRE.WORD = ipr[4];
INTX.IPRF.WORD = ipr[5];
INTX.IPRG.WORD = ipr[6];
INTX.IPRH.WORD = ipr[7];
INTX.IPRI.WORD = ipr[8];
INTX.IPRJ.WORD = ipr[9];
INTX.IPRK.WORD = ipr[10];
INTX.IPRL.WORD = ipr[11];
// Restoring keyboard registers.
*((volatile unsigned short *)0xa4050116) = inj1;
*((volatile unsigned char *)0xa4050136) = data1;
*((volatile unsigned short *)0xa4050118) = inj2;
*((volatile unsigned char *)0xa4050138) = data2;
*((volatile unsigned short *)0xa405014c) = det;
*((volatile unsigned char *)0xa405016c) = keys;
*((volatile unsigned char *)0xa40501c6) = reg;
}
void gint_setup_7305(void)
{
gint_priority_lock_7305();
// Configuring the RTC to have a 16-Hz keyboard.
rcr2 = RTC.RCR2.BYTE;
RTC.RCR2.BYTE = 0x39;
}
void gint_stop_7305(void)
{
gint_priority_unlock_7305();
// Stopping the RTC interrupt.
RTC.RCR2.BYTE = rcr2;
}