parent
							
								
									e2afc305ed
								
							
						
					
					
						commit
						3f0289e666
					
				| @ -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(); | ||||
| } | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
| After Width: | Height: | Size: 48 KiB | 
| After Width: | Height: | Size: 49 KiB | 
| @ -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))]); | ||||
| } | ||||
| @ -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) | ||||
| { | ||||
| } | ||||
| @ -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)); | ||||
|     } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue
	
	 tmk
						tmk