キースキャン処理
んー、もしかして row と column って逆なのかな。チャージの意味も逆かもしれないなぁ。
バグがあったので修正。
typedef int key_scan_code_t;
#define KS_POWER 0xad /* Power key */
#define CS2_ADDRESS 0x08000000
#define KBDCOL_L (CS2_ADDRESS + 0x00) /* Write */
#define KBDCOL_U (CS2_ADDRESS + 0x04) /* Write */
#define KBDCHARGE (CS2_ADDRESS + 0x08) /* Write */
#define KBDDATA (CS2_ADDRESS + 0x08) /* Read */
#define MAXPRESS 10 /* キー同時最大押下数 */
#define NCOLUMN 12 /* キーマトリックス桁数 */
#define NROW 7 /* キーマトリックス行数 */
#define KEYWAIT 10 /* wait (ms?) (OS Timer のカウンタで KEYWAIT * 4000 分待つ) */
/*
* キースキャンコードテーブル
*
* 0x30d0-0x30e8: copy 8192 * 16 (=128Ki) byte from address 0(ROM) to 0xa00a0000(SDRAM).
* キースキャンコードのテーブルは SDRAM 上では 0xa00a1758 に存在するので、
* ROM 上のアドレスに変換すると 0x1758 になる。
*/
static const key_scan_code_t key_scan_code_tbl[NCOLUMN][NROW] = {
{ 0x84, 0x31, 0x33, 0x35, 0x36, 0x37, 0x39, },
{ 0x30, 0x08, 0x00, 0xdb, 0xd6, 0x00, 0x32, },
{ 0x34, 0x52, 0x59, 0x38, 0x49, 0x4f, 0x50, },
{ 0x00, 0xd8, 0xd7, 0x09, 0x51, 0x45, 0x54, },
{ 0x47, 0x55, 0x4a, 0x4b, 0x00, 0x00, 0x00, },
{ 0x00, 0x00, 0x57, 0x53, 0x46, 0x56, 0x48, },
{ 0x4d, 0x4c, 0x00, 0x00, 0xd5, 0x00, 0xde, },
{ 0x41, 0x44, 0x43, 0x42, 0x4e, 0x2e, 0x00, },
{ 0x0d, 0x00, 0xdc, 0x00, 0xab, 0x5a, 0x58, },
{ 0x2d, 0x20, 0x2f, 0x00, 0x8b, 0x00, 0x00, },
{ 0xd9, 0x85, 0xdd, 0xcf, 0x00, 0xa7, 0xa8, },
{ 0x2c, 0x8c, 0x8a, 0x8d, 0x00, 0xda, 0x00, },
};
/**
* \brief
* 押下キーを検出して、キーバッファに押下キースキャンコードを格納する。
*
* キーマトリックスを走査し押下キーを検出して、keybuf に押下キーの
* スキャンコードを格納する。<br>
* また、キーマトリックス走査の他に GPIO<95> のレベルを取得し Hi レベルで
* あれば電源キーのスキャンコードを keybuf に格納する。<br>
* 押下キーが nkeybuf に指定された値、もしくはコンパイル時に指定された値
* (MAXPRESS) よりも多く検出された場合、キー押下は無かったものとして扱われる。
*
* \param nkeybuf キーバッファ数
* \param keybuf キースキャンコードを格納するメモリ領域へのポインタ。
* 呼び出し側で nkeybuf 個数分のメモリを確保しなければならない。
* \return 押下キー数
*/
int
keyscan(int nkeybuf, key_scan_code_t *keybuf)
{
struct {
int col;
int row;
} key[MAXPRESS];
key_scan_code_t *keybufp;
int row, col;
int npress;
int data;
int powerkey;
int i;
_ASSERT(0 < nkeybuf);
_ASSERT(keybuf != NULL);
if (nkeybuf > MAXPRESS)
nkeybuf = MAXPRESS;
/* get GPIO<95> level sense (maybe check power-key pressed...) */
powerkey = GPIO_GPLR(95);
npress = 0;
for (col = 0; col < NCOLUMN; col++) {
/* deselect column# and charge */
CSR_WRITE1(KBDCOL_L, 0);
CSR_WRITE1(KBDCOL_U, 0);
CSR_WRITE1(KBDCHARGE, 1);
delay(KEYWAIT);
/* discharge & select scan column# */
CSR_WRITE1(KBDCHARGE, 0);
if (col < 8/*NCHAR_BIT*/) {
CSR_WRITE1(KBDCOL_L, 1U << col);
CSR_WRITE1(KBDCOL_U, 0);
} else {
CSR_WRITE1(KBDCOL_L, 0);
CSR_WRITE1(KBDCOL_U, 1U << (col - 8));
}
delay(KEYWAIT);
for (row = 0; row < NROW; row++) {
CSR_WRITE1(KBDCHARGE, 0);
data = CSR_READ1(KBDDATA);
if ((data >> row) & 1) {
/* detect key press */
if (npress >= MAXPRESS) {
npress = 0;
goto nokeypress;
}
key[npress].col = col;
key[npress].row = row;
npress++;
}
}
}
if (npress >= nkeybuf) {
npress = 0;
goto nokeypress;
}
keybufp = keybuf;
if (powerkey) {
if (npress + 1 >= nkeybuf) {
npress = 0;
goto nokeypress;
}
keybufp++;
}
/* column/row -> key scan code */
for (i = 0; i < npress; i++) {
keybufp[i] = key_scan_code_tbl[key[i].col][key[i].row];
}
if (powerkey) {
keybuf[0] = KS_POWER;
npress++;
}
nokeypress:
/* deselect column# and charge */
CSR_WRITE1(KBDCOL_L, 0);
CSR_WRITE1(KBDCOL_U, 0);
CSR_WRITE1(KBDCHARGE, 1);
delay(KEYWAIT);
/* discharge for power management */
CSR_WRITE1(KBDCHARGE, 0);
return npress;
}