Browse Source

Added protocol support for Macintosh keyboard M0110.

tmk 14 năm trước cách đây
mục cha
commit
3f0289e666
10 tập tin đã thay đổi với 881 bổ sung0 xóa
  1. 304 0
      m0110.c
  2. 73 0
      m0110.h
  3. 52 0
      m0110_usb/Makefile
  4. 55 0
      m0110_usb/README
  5. 62 0
      m0110_usb/config.h
  6. BIN
      m0110_usb/doc/m0110.jpg
  7. BIN
      m0110_usb/doc/teensy.jpg
  8. 118 0
      m0110_usb/keymap.c
  9. 24 0
      m0110_usb/led.c
  10. 193 0
      m0110_usb/matrix.c

+ 304 - 0
m0110.c

@@ -0,0 +1,304 @@
+/*
+Copyright 2011 Jun WAKO <wakojun@gmail.com>
+
+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 <stdbool.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include "m0110.h"
+#include "debug.h"
+
+
+static inline void clock_lo(void);
+static inline void clock_hi(void);
+static inline bool clock_in(void);
+static inline void data_lo(void);
+static inline void data_hi(void);
+static inline bool data_in(void);
+static inline uint16_t wait_clock_lo(uint16_t us);
+static inline uint16_t wait_clock_hi(uint16_t us);
+static inline uint16_t wait_data_lo(uint16_t us);
+static inline uint16_t wait_data_hi(uint16_t us);
+static inline void idle(void);
+static inline void request(void);
+
+
+/*
+Primitive M0110 Library for AVR
+==============================
+
+
+Signaling
+---------
+CLOCK is always from KEYBOARD. DATA are sent with MSB first.
+
+1) IDLE: both line is high.
+    CLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    DATA  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+2) KEYBOARD->HOST: HOST reads bit on rising edge.
+    CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
+    DATA  ~~~~~~~~~~~~X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
+                      <--> 160us(clock low)
+                         <---> 180us(clock high)
+
+3) HOST->KEYBOARD: HOST asserts bit on falling edge.
+    CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
+    DATA  ~~~~~~|_____X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
+                <----> 840us(request to send by host)                     <-> 80us(hold DATA)
+                      <--> 180us(clock low)
+                         <---> 220us(clock high)
+
+
+Protocol
+--------
+COMMAND:
+    Inquiry     0x10    get key event
+    Instant     0x12    get key event
+    Model       0x14    get model number(M0110 responds with 0x09)
+                        bit 7   1 if another device connected(used when keypad exists?)
+                        bit4-6  next device model number
+                        bit1-3  keyboard model number
+                        bit 0   always 1
+    Test        0x16    test(ACK:0x7D/NAK:0x77)
+
+KEY EVENT:
+    bit 7       key state(0:press 1:release)
+    bit 6-1     scan code
+    bit 0       always 1
+    To get scan code,  use ((bits&(1<<7)) | ((bits&7F))>>1).
+
+SCAN CODE:
+    M0110A
+    ,---------------------------------------------------------.
+    |  `|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|Backs|
+    |---------------------------------------------------------|
+    |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|  \|
+    |---------------------------------------------------------|
+    |CapsLo|  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  '|Return|
+    |---------------------------------------------------------|
+    |Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  ,|  /|        |
+    `---------------------------------------------------------'
+         |Opt|Mac |         Space               |Enter|Opt|
+         `------------------------------------------------'
+    ,---------------------------------------------------------.
+    | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18|   33|
+    |---------------------------------------------------------|
+    |   30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| 2A|
+    |---------------------------------------------------------|
+    |    39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27|    24|
+    |---------------------------------------------------------|
+    |      38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C|      38|
+    `---------------------------------------------------------'
+         | 3A|  37|             31              |   34| 3A|
+         `------------------------------------------------'
+
+
+References
+----------
+Protocol:
+    http://www.mac.linux-m68k.org/devel/plushw.php
+Connector:
+    http://www.kbdbabel.org/conn/kbd_connector_macplus.png
+Signaling:
+    http://www.kbdbabel.org/signaling/kbd_signaling_mac.png
+    http://typematic.blog.shinobi.jp/Entry/14/
+Scan Codes:
+    http://m0115.web.fc2.com/m0110.jpg
+    http://m0115.web.fc2.com/m0110a.jpg
+*/
+
+
+#define WAIT(stat, us, err) do { \
+    if (!wait_##stat(us)) { \
+        m0110_error = err; \
+        goto ERROR; \
+    } \
+} while (0)
+
+
+uint8_t m0110_error = 0;
+
+
+void m0110_init(void)
+{
+    uint8_t data;
+    idle();
+    _delay_ms(255);
+
+    m0110_send(M0110_MODLE);
+    data = m0110_recv();
+    print("m0110_init model: "); phex(data); print("\n");
+
+    m0110_send(M0110_TEST);
+    data = m0110_recv();
+    print("m0110_init test: "); phex(data); print("\n");
+}
+
+uint8_t m0110_send(uint8_t data)
+{
+    m0110_error = 0;
+
+    request();
+    WAIT(clock_lo, 1000, 0);
+    for (uint8_t bit = 0x80; bit; bit >>= 1) {
+        WAIT(clock_lo, 250, 3);
+        _delay_us(15);
+        if (data&bit) {
+            data_hi();
+        } else {
+            data_lo();
+        }
+        WAIT(clock_hi, 200, 4);
+    }
+    _delay_us(100); // hold last bit for 80us
+    idle();
+    return 1;
+ERROR:
+    if (m0110_error) {
+        print("m0110_send err: "); phex(m0110_error); print("\n");
+    }
+    idle();
+    return 0;
+}
+
+uint8_t m0110_recv(void)
+{
+    uint8_t data = 0;
+    m0110_error = 0;
+
+    WAIT(clock_lo, -1, 0); // need 250ms? insted 0xffff(16bit max)us
+    for (uint8_t i = 0; i < 8; i++) {
+        data <<= 1;
+        WAIT(clock_lo, 200, 2);
+        WAIT(clock_hi, 200, 3);
+        if (data_in()) {
+            data |= 1;
+        }
+    }
+    idle();
+    print("m0110_send recv data: "); phex(data); print("\n");
+    return data;
+ERROR:
+    if (m0110_error) {
+        print("m0110_recv err: "); phex(m0110_error); print("\n");
+    }
+    idle();
+    return 0xFF;
+}
+
+uint8_t m0110_recv_key(void)
+{
+    uint8_t key;
+    m0110_send(M0110_INQUIRY);
+    key = m0110_recv();
+    if (key == 0xFF || key == M0110_NULL)
+        return M0110_NULL;
+    else 
+        return (key&(1<<7) | (key&0x7F)>>1);
+}
+
+
+static inline void clock_lo()
+{
+    M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
+    M0110_CLOCK_DDR  |=  (1<<M0110_CLOCK_BIT);
+}
+static inline void clock_hi()
+{
+    /* input with pull up */
+    M0110_CLOCK_DDR  &= ~(1<<M0110_CLOCK_BIT);
+    M0110_CLOCK_PORT |=  (1<<M0110_CLOCK_BIT);
+}
+static inline bool clock_in()
+{
+    M0110_CLOCK_DDR  &= ~(1<<M0110_CLOCK_BIT);
+    M0110_CLOCK_PORT |=  (1<<M0110_CLOCK_BIT);
+    _delay_us(1);
+    return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
+}
+static inline void data_lo()
+{
+    M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
+    M0110_DATA_DDR  |=  (1<<M0110_DATA_BIT);
+}
+static inline void data_hi()
+{
+    /* input with pull up */
+    M0110_DATA_DDR  &= ~(1<<M0110_DATA_BIT);
+    M0110_DATA_PORT |=  (1<<M0110_DATA_BIT);
+}
+static inline bool data_in()
+{
+    M0110_DATA_DDR  &= ~(1<<M0110_DATA_BIT);
+    M0110_DATA_PORT |=  (1<<M0110_DATA_BIT);
+    _delay_us(1);
+    return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
+}
+
+static inline uint16_t wait_clock_lo(uint16_t us)
+{
+    while (clock_in()  && us) { asm(""); _delay_us(1); us--; }
+    return us;
+}
+static inline uint16_t wait_clock_hi(uint16_t us)
+{
+    while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
+    return us;
+}
+static inline uint16_t wait_data_lo(uint16_t us)
+{
+    while (data_in() && us)  { asm(""); _delay_us(1); us--; }
+    return us;
+}
+static inline uint16_t wait_data_hi(uint16_t us)
+{
+    while (!data_in() && us)  { asm(""); _delay_us(1); us--; }
+    return us;
+}
+
+static inline void idle(void)
+{
+    clock_hi();
+    data_hi();
+}
+
+static inline void request(void)
+{
+    clock_hi();
+    data_lo();
+}

+ 73 - 0
m0110.h

@@ -0,0 +1,73 @@
+/*
+Copyright 2011 Jun WAKO <wakojun@gmail.com>
+
+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.
+*/
+
+#ifndef M0110_H
+#define M0110_H
+
+
+/* port settings for clock and data line */
+#if !(defined(M0110_CLOCK_PORT) && \
+      defined(M0110_CLOCK_PIN) && \
+      defined(M0110_CLOCK_DDR) && \
+      defined(M0110_CLOCK_BIT))
+#   error "M0110 clock port setting is required in config.h"
+#endif
+
+#if !(defined(M0110_DATA_PORT) && \
+      defined(M0110_DATA_PIN) && \
+      defined(M0110_DATA_DDR) && \
+      defined(M0110_DATA_BIT))
+#   error "M0110 data port setting is required in config.h"
+#endif
+
+#define M0110_INQUIRY     0x10
+#define M0110_INSTNAT     0x14
+#define M0110_MODLE       0x16
+#define M0110_TEST        0x36
+
+#define M0110_NULL        0x7B
+
+
+extern uint8_t m0110_error;
+
+/* host role */
+void m0110_host_init(void);
+uint8_t m0110_send(uint8_t data);
+uint8_t m0110_recv(void);
+uint8_t m0110_recv_key(void);
+
+#endif

+ 52 - 0
m0110_usb/Makefile

@@ -0,0 +1,52 @@
+# Target file name (without extension).
+TARGET = m0110
+
+# Directory common source filess exist
+COMMON_DIR = ..
+
+# Directory keyboard dependent files exist
+TARGET_DIR = .
+
+# keyboard dependent files
+SRC =	main.c \
+	keymap.c \
+	matrix.c \
+	led.c \
+	m0110.c
+
+CONFIG_H = config.h
+
+
+# MCU name, you MUST set this to match the board you are using
+# type "make clean" after changing this, so all files will be rebuilt
+#MCU = at90usb162       # Teensy 1.0
+MCU = atmega32u4       # Teensy 2.0
+#MCU = at90usb646       # Teensy++ 1.0
+#MCU = at90usb1286      # Teensy++ 2.0
+
+
+# Processor frequency.
+#   Normally the first thing your program should do is set the clock prescaler,
+#   so your program will run at the correct speed.  You should also set this
+#   variable to same clock speed.  The _delay_ms() macro uses this, and many
+#   examples use this variable to calculate timings.  Do not add a "UL" here.
+F_CPU = 16000000
+
+
+# Build Options
+#   *Comment out* to disable the options.
+#
+#MOUSEKEY_ENABLE = yes	# Mouse keys
+#PS2_MOUSE_ENABLE = yes	# PS/2 mouse(TrackPoint) support
+#EXTRAKEY_ENABLE = yes	# Audio control and System control
+#NKRO_ENABLE = yes	# USB Nkey Rollover
+
+
+
+#---------------- Programming Options --------------------------
+PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
+
+
+
+include $(COMMON_DIR)/pjrc.mk
+include $(COMMON_DIR)/common.mk

+ 55 - 0
m0110_usb/README

@@ -0,0 +1,55 @@
+M0110 to USB keyboard converter
+===============================
+This firmware converts protocol for Apple Machintosh Keybard M0110.
+
+
+Connection
+----------
+You need 4P4C plug and cable to connect Teensy into M0110.
+Teensy port F0 is assigned for CLOCK line and F1 for DATA by default, you can change pin configuration with editing config.h..
+
+Plug:
+    http://en.wikipedia.org/wiki/Modular_connector#4P4C
+
+Pinout:
+    http://www.kbdbabel.org/conn/kbd_connector_macplus.png
+    1(Black):   GND
+    2(Red):     CLOCK
+    3(Green):   DATA
+    4(Yellow):  +5V
+
+
+
+Build Frimware
+--------------
+Optionally edit Makefile and config.h for build options, pin configuration or MCU.
+
+$ cd m0110_usb
+$ make
+and program your Teensy with loader.
+
+
+
+Keymap
+------
+You can change a keymap by editing code of keymap.c like following.
+How to define the keymap is probably obvious. You can find  key symbols in usb_keycodes.h.
+
+This is a default keymap for M0110.
+,---------------------------------------------------------.
+|  `|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|Bacpa|
+|---------------------------------------------------------|
+|Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|  \|
+|---------------------------------------------------------|
+|CapsLo|  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  '|Return|
+|---------------------------------------------------------|
+|Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  ,|  /|Shift   |
+`---------------------------------------------------------'
+     |Opt|Alt |         Space               |Alt |Opt|
+     `-----------------------------------------------'
+
+
+Notes
+-----
+
+EOF

+ 62 - 0
m0110_usb/config.h

@@ -0,0 +1,62 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* controller configuration */
+#include "controller_teensy.h"
+
+
+#define VENDOR_ID       0xFEED
+#define PRODUCT_ID      0x0110
+#define MANUFACTURER    t.m.k.
+#define PRODUCT         M0110 keyboard converter
+#define DESCRIPTION     convert M0110 keyboard to USB
+
+
+/* matrix size */
+#define MATRIX_ROWS 8
+#define MATRIX_COLS 8
+
+/* Locking Caps Lock support */
+//#define MATRIX_HAS_LOCKING_CAPS
+
+/* key combination for command */
+#define IS_COMMAND() ( \
+    keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_LCTRL) | MOD_BIT(KB_LALT) | MOD_BIT(KB_LGUI)) || \
+    keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) \
+)
+
+
+/* mouse keys */
+#ifdef MOUSEKEY_ENABLE
+#   define MOUSEKEY_DELAY_TIME 192
+#endif
+
+
+/* ports */
+#define M0110_CLOCK_PORT        PORTF
+#define M0110_CLOCK_PIN         PINF
+#define M0110_CLOCK_DDR         DDRF
+#define M0110_CLOCK_BIT         0
+#define M0110_DATA_PORT         PORTF
+#define M0110_DATA_PIN          PINF
+#define M0110_DATA_DDR          DDRF
+#define M0110_DATA_BIT          1
+
+#endif

BIN
m0110_usb/doc/m0110.jpg


BIN
m0110_usb/doc/teensy.jpg


+ 118 - 0
m0110_usb/keymap.c

@@ -0,0 +1,118 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* 
+ * Keymap for ADB keyboard
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/pgmspace.h>
+#include "usb_keyboard.h"
+#include "usb_keycodes.h"
+#include "print.h"
+#include "debug.h"
+#include "util.h"
+#include "keymap.h"
+
+
+#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
+
+// Convert physical keyboard layout to matrix array.
+// This is a macro to define keymap easily in keyboard layout form.
+// TODO: layout for M0110A
+/* M0110 */
+#define KEYMAP( \
+    K32,K12,K13,K14,K15,K17,K16,K1A,K1C,K19,K1D,K1B,K18,K33, \
+    K30,K0C,K0D,K0E,K0F,K11,K10,K20,K22,K1F,K23,K21,K1E,K2A, \
+    K39,K00,K01,K02,K03,K05,K04,K26,K28,K25,K29,K27,    K24, \
+    K38,K06,K07,K08,K09,K0B,K2D,K2E,K2B,K2F,K2C,             \
+        K3A,K37,        K31,                K34              \
+) { \
+    { KB_##K00, KB_##K01, KB_##K02, KB_##K03, KB_##K04, KB_##K05, KB_##K06, KB_##K07 }, \
+    { KB_##K08, KB_##K09, KB_NO,    KB_##K0B, KB_##K0C, KB_##K0D, KB_##K0E, KB_##K0F }, \
+    { KB_##K10, KB_##K11, KB_##K12, KB_##K13, KB_##K14, KB_##K15, KB_##K16, KB_##K17 }, \
+    { KB_##K18, KB_##K19, KB_##K1A, KB_##K1B, KB_##K1C, KB_##K1D, KB_##K1E, KB_##K1F }, \
+    { KB_##K20, KB_##K21, KB_##K22, KB_##K23, KB_##K24, KB_##K25, KB_##K26, KB_##K27 }, \
+    { KB_##K28, KB_##K29, KB_##K2A, KB_##K2B, KB_##K2C, KB_##K2D, KB_##K2E, KB_##K2F }, \
+    { KB_##K30, KB_##K31, KB_##K32, KB_##K33, KB_##K34, KB_NO,    KB_NO,    KB_##K37 }, \
+    { KB_##K38, KB_##K39, KB_##K3A, KB_NO,    KB_NO,    KB_NO,    KB_NO,    KB_NO    }  \
+}
+
+
+// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
+static const uint8_t PROGMEM fn_layer[] = {
+    0,              // Fn0
+    0,              // Fn1
+    0,              // Fn2
+    0,              // Fn3
+    0,              // Fn4
+    0,              // Fn5
+    0,              // Fn6
+    0               // Fn7
+};
+
+// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
+// See layer.c for details.
+static const uint8_t PROGMEM fn_keycode[] = {
+    KB_NO,          // Fn0
+    KB_NO,          // Fn1
+    KB_NO,          // Fn2
+    KB_NO,          // Fn3
+    KB_NO,          // Fn4
+    KB_NO,          // Fn5
+    KB_NO,          // Fn6
+    KB_NO           // Fn7
+};
+
+static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+    /* Default Layer: plain keymap
+     * ,---------------------------------------------------------.
+     * |  `|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|Bacpa|
+     * |---------------------------------------------------------|
+     * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|  \|
+     * |---------------------------------------------------------|
+     * |CapsLo|  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  '|Return|
+     * |---------------------------------------------------------|
+     * |Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  ,|  /|Shift   |
+     * `---------------------------------------------------------'
+     *      |Opt|Alt |         Space               |Alt |Opt|
+     *      `-----------------------------------------------'
+     */
+    KEYMAP(
+    GRV, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSPC,
+    TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSLS,
+    CAPS,A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN,QUOT,     ENT,
+    LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,
+         LGUI,LALT,          SPC,                     RALT
+    ),
+};
+
+
+uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
+{
+    return KEYCODE(layer, row, col);
+}
+
+uint8_t keymap_fn_layer(uint8_t fn_bits)
+{
+    return pgm_read_byte(&fn_layer[biton(fn_bits)]);
+}
+
+uint8_t keymap_fn_keycode(uint8_t fn_bits)
+{
+    return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
+}

+ 24 - 0
m0110_usb/led.c

@@ -0,0 +1,24 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdint.h"
+#include "led.h"
+
+
+void led_set(uint8_t usb_led)
+{
+}

+ 193 - 0
m0110_usb/matrix.c

@@ -0,0 +1,193 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * scan matrix
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/io.h>
+#include <util/delay.h>
+#include "print.h"
+#include "util.h"
+#include "debug.h"
+#include "host.h"
+#include "led.h"
+#include "m0110.h"
+#include "matrix.h"
+
+
+#define CAPS        0x39
+#define CAPS_UP     (CAPS | 0x80)
+#define ROW(key)    ((key)>>3&0x0F)
+#define COL(key)    ((key)&0x07)
+
+
+static bool is_modified = false;
+
+// matrix state buffer(1:on, 0:off)
+static uint8_t *matrix;
+static uint8_t _matrix0[MATRIX_ROWS];
+
+#ifdef MATRIX_HAS_GHOST
+static bool matrix_has_ghost_in_row(uint8_t row);
+#endif
+static void register_key(uint8_t key);
+
+
+inline
+uint8_t matrix_rows(void)
+{
+    return MATRIX_ROWS;
+}
+
+inline
+uint8_t matrix_cols(void)
+{
+    return MATRIX_COLS;
+}
+
+void matrix_init(void)
+{
+    print_enable = true;
+    debug_enable = true;
+    debug_matrix = false;
+    debug_keyboard = false;
+    debug_mouse = false;
+    print("debug enabled.\n");
+
+    m0110_init();
+    // initialize matrix state: all keys off
+    for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
+    matrix = _matrix0;
+    return;
+}
+
+uint8_t matrix_scan(void)
+{
+    uint8_t key;
+
+    is_modified = false;
+    key = m0110_recv_key();
+
+#ifdef MATRIX_HAS_LOCKING_CAPS
+    // Send Caps key up event
+    if (matrix_is_on(ROW(CAPS), COL(CAPS))) {
+        is_modified = true;
+        register_key(CAPS_UP);
+    }
+#endif
+    if (key == M0110_NULL) {
+        return 0;
+    } else {
+#ifdef MATRIX_HAS_LOCKING_CAPS    
+        if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) {
+            // CAPS LOCK on:
+            // Ignore LockingCaps key down event
+            if (key == CAPS) return 0;
+            // Convert LockingCaps key up event into down event
+            if (key == CAPS_UP) key = CAPS;
+        } else {
+            // CAPS LOCK off:
+            // Ignore LockingCaps key up event
+            if (key == CAPS_UP) return 0;
+        }
+#endif        
+        is_modified = true;
+        register_key(key);
+    }
+
+    if (debug_enable) {
+        print("key: "); phex(key); print("\n");
+    }
+    return 1;
+}
+
+bool matrix_is_modified(void)
+{
+    return is_modified;
+}
+
+inline
+bool matrix_has_ghost(void)
+{
+#ifdef MATRIX_HAS_GHOST
+    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+        if (matrix_has_ghost_in_row(i))
+            return true;
+    }
+#endif
+    return false;
+}
+
+inline
+bool matrix_is_on(uint8_t row, uint8_t col)
+{
+    return (matrix[row] & (1<<col));
+}
+
+inline
+uint8_t matrix_get_row(uint8_t row)
+{
+    return matrix[row];
+}
+
+void matrix_print(void)
+{
+    print("\nr/c 01234567\n");
+    for (uint8_t row = 0; row < matrix_rows(); row++) {
+        phex(row); print(": ");
+        pbin_reverse(matrix_get_row(row));
+        print("\n");
+    }
+}
+
+uint8_t matrix_key_count(void)
+{
+    uint8_t count = 0;
+    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+        count += bitpop(matrix[i]);
+    }
+    return count;
+}
+
+#ifdef MATRIX_HAS_GHOST
+inline
+static bool matrix_has_ghost_in_row(uint8_t row)
+{
+    // no ghost exists in case less than 2 keys on
+    if (((matrix[row] - 1) & matrix[row]) == 0)
+        return false;
+
+    // ghost exists in case same state as other row
+    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
+        if (i != row && (matrix[i] & matrix[row]) == matrix[row])
+            return true;
+    }
+    return false;
+}
+#endif
+
+inline
+static void register_key(uint8_t key)
+{
+    if (key&0x80) {
+        matrix[ROW(key)] &= ~(1<<COL(key));
+    } else {
+        matrix[ROW(key)] |=  (1<<COL(key));
+    }
+}