diff options
Diffstat (limited to 'converter/next_usb/matrix.c')
-rw-r--r-- | converter/next_usb/matrix.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/converter/next_usb/matrix.c b/converter/next_usb/matrix.c new file mode 100644 index 0000000000..fd6eb9d64f --- /dev/null +++ b/converter/next_usb/matrix.c @@ -0,0 +1,269 @@ +/* +NeXT non-ADB Keyboard USB Converter + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +TMK firmware code Copyright 2011,2012 Jun WAKO <wakojun@gmail.com> +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include <util/delay.h> +#include "print.h" +#include "util.h" +#include "serial.h" +#include "matrix.h" +#include "debug.h" +#include "matrix.h" +#include "next_kbd.h" + +static void matrix_make(uint8_t code); +static void matrix_break(uint8_t code); + +static uint8_t matrix[MATRIX_ROWS]; +#define ROW(code) ((code>>3)&0xF) +#define COL(code) (code&0x07) + +static bool is_modified = false; + +/* number of matrix rows */ +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +/* number of matrix columns */ +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +#ifndef NEXT_KBD_LED1_ON +#define NEXT_KBD_LED1_ON +#endif + +#ifndef NEXT_KBD_LED1_OFF +#define NEXT_KBD_LED1_OFF +#endif + +#define NEXT_KBD_PWR_READ (NEXT_KBD_PWR_PIN&(1<<NEXT_KBD_PWR_BIT)) + +static bool power_state = false; + +/* intialize matrix for scanning. should be called once. */ +void matrix_init(void) +{ +#ifdef DEBUG_ON_INIT + debug_enable = true; +#endif + + // I've found that the matrix likes a little while for things to + // settle down before it gets started. Not sure why :) + _delay_ms(250); + + dprintf("[ Intializing NeXT keyboard ]\n"); + NEXT_KBD_LED1_DDR |= (1<<NEXT_KBD_LED1_BIT); // LED pin to output + NEXT_KBD_LED1_ON; + + NEXT_KBD_PWR_DDR &= ~(1<<NEXT_KBD_PWR_BIT); // Power Button pin to input + NEXT_KBD_PWR_PIN |= (1<<NEXT_KBD_PWR_BIT); // KBD_PWR pull up + + power_state = NEXT_KBD_PWR_READ ? false : true; + dprintf("Initial power button state: %b\n", power_state); + + next_kbd_init(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; + +#ifdef NEXT_KBD_INIT_FLASH_LEDS + dprintf("flashing LEDs:"); + // flash the LEDs after initialization + bool leds_on = true; + for (uint8_t i = 0; i <= 6; i++) + { + leds_on = leds_on ? false : true; + dprintf(" %b", leds_on); + next_kbd_set_leds(leds_on, leds_on); + _delay_ms(250); + } + dprintf("\n"); +#endif + + dprintf("[ NeXT keyboard initialized ]\n"); + + return; +} + +#define NEXT_KBD_KEYCODE(response) (uint8_t)((response&0xFF)>>1) +#define NEXT_KBD_PRESSED_KEYCODE(response) (uint8_t)(((response)&0xF00)==0x400) +#define NEXT_KBD_PRESSED(response, mask) (uint8_t)(((response)&mask)>0) +#define NEXT_KBD_PRESSED_CONTROL(response) NEXT_KBD_PRESSED(response,0x01000) +#define NEXT_KBD_PRESSED_SHIFT_LEFT(response) NEXT_KBD_PRESSED(response,0x02000) +#define NEXT_KBD_PRESSED_SHIFT_RGHT(response) NEXT_KBD_PRESSED(response,0x04000) +#define NEXT_KBD_PRESSED_CMD_LEFT(response) NEXT_KBD_PRESSED(response,0x08000) +#define NEXT_KBD_PRESSED_CMD_RGHT(response) NEXT_KBD_PRESSED(response,0x10000) +#define NEXT_KBD_PRESSED_ALT_LEFT(response) NEXT_KBD_PRESSED(response,0x20000) +#define NEXT_KBD_PRESSED_ALT_RGHT(response) NEXT_KBD_PRESSED(response,0x40000) +#define NEXT_KBD_MAKE_OR_BREAK(key, code) \ + do { \ + if (NEXT_KBD_PRESSED_##key(resp) > 0) \ + matrix_make(code); \ + else \ + matrix_break(code); \ + } while (0); + +#define NEXT_KBD_PWR_KEYCODE 0x58 + +/* scan all key states on matrix */ +uint8_t matrix_scan(void) +{ + _delay_ms(20); + + //next_kbd_set_leds(false, false); + NEXT_KBD_LED1_OFF; + + is_modified = false; + + if (!NEXT_KBD_PWR_READ) { + matrix_make(NEXT_KBD_PWR_KEYCODE); + power_state = 1; + if (is_modified) + { + dprintf("Power state 1\n"); + + } + } else { + matrix_break(NEXT_KBD_PWR_KEYCODE); + power_state = 0; + if (is_modified) + { + dprintf("Power state 0\n"); + + } + } + + uint32_t resp = (next_kbd_recv()); + + if (resp == NEXT_KBD_KMBUS_IDLE) + { + return 0; + } + + NEXT_KBD_LED1_ON; + + next_kbd_set_leds( + NEXT_KBD_PRESSED_SHIFT_LEFT(resp) ? true : false, + NEXT_KBD_PRESSED_SHIFT_RGHT(resp) ? true : false + ); + + dprintf("[ r=%04lX keycode=%02X pressed=%X CTRL=%X SHIFT_LEFT=%X SHIFT_RGHT=%X CMD_LEFT=%X CMD_RGHT=%X ALT_LEFT=%X ALT_RGHT=%X ]\n", \ + resp, \ + NEXT_KBD_KEYCODE(resp), \ + NEXT_KBD_PRESSED_KEYCODE(resp), \ + NEXT_KBD_PRESSED_CONTROL(resp), \ + NEXT_KBD_PRESSED_SHIFT_LEFT(resp), \ + NEXT_KBD_PRESSED_SHIFT_RGHT(resp), \ + NEXT_KBD_PRESSED_CMD_LEFT(resp), \ + NEXT_KBD_PRESSED_CMD_RGHT(resp), \ + NEXT_KBD_PRESSED_ALT_LEFT(resp), \ + NEXT_KBD_PRESSED_ALT_RGHT(resp) \ + ); + + // Modifier keys don't return keycode; have to check the upper bits + NEXT_KBD_MAKE_OR_BREAK(ALT_RGHT, 0x51); + NEXT_KBD_MAKE_OR_BREAK(ALT_LEFT, 0x52); + NEXT_KBD_MAKE_OR_BREAK(CMD_RGHT, 0x53); + NEXT_KBD_MAKE_OR_BREAK(CMD_LEFT, 0x54); + NEXT_KBD_MAKE_OR_BREAK(SHIFT_RGHT, 0x55); + NEXT_KBD_MAKE_OR_BREAK(SHIFT_LEFT, 0x56); + NEXT_KBD_MAKE_OR_BREAK(CONTROL, 0x57); + NEXT_KBD_MAKE_OR_BREAK(KEYCODE, NEXT_KBD_KEYCODE(resp)); + + return 1; +} + +/* whether modified from previous scan. used after matrix_scan. */ +bool matrix_is_modified() +{ + return is_modified; +} + +/* whether a switch is on */ +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1<<col)); +} + +/* matrix state on row */ +inline +uint8_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +/* print matrix for debug */ +void matrix_print(void) +{ +} + +inline +static void matrix_make(uint8_t code) +{ + if (!matrix_is_on(ROW(code), COL(code))) { + matrix[ROW(code)] |= 1<<COL(code); + is_modified = true; + } +} + +inline +static void matrix_break(uint8_t code) +{ + if (matrix_is_on(ROW(code), COL(code))) { + matrix[ROW(code)] &= ~(1<<COL(code)); + is_modified = true; + } +} |