Compare commits

...

70 Commits
v2.0 ... master

Author SHA1 Message Date
Travis Burtrum c2bcad5149 Change default layout to qwerty, and layout changing keys to LCTRL + RCTRL to not conflict with rusty-keys 2018-10-22 00:19:30 -04:00
Travis Burtrum 11db1e1a9f Update pjrc lib to compile with modern avr-gcc 2018-10-22 00:17:53 -04:00
Travis Burtrum d831eb699b Updated README to reflect what this fork specifically accomplishes. 2011-05-31 12:22:14 -04:00
Travis Burtrum a77a1d2289 Merge remote branch 'upstream/master'
Conflicts:
	keyboard.c
	ps2_usb/keymap.c
2011-05-31 12:19:19 -04:00
tmk 6d45e05ede Added PS/2 multimeda key support.
HID Consumer page and System control are also supported now.
merged mediakey branch: d53a356cd2011b461843a5c7c1527a61692893c1
2011-05-31 21:25:16 +09:00
Travis Burtrum 47da6bf7d4 Added keymap support for volume control, and a function to print ints in decimal format.
I'm now stuck until I find the specification for keys like next track, stop, play/pause,
browser controls and the like, anyone?
2011-05-26 01:31:49 -04:00
Travis Burtrum 98edc2fcbc First commit. Added dvorak-qwerty switching with scroll lock led indicator, and ctrl button switches back to qwerty for shortcuts. Also added dvorak layout with layer switching. 2011-05-25 11:49:22 -04:00
tmk af85b6bba6 added HHKB/README and clean some codes. 2011-05-25 11:30:14 +09:00
tmk 74f7e19863 added USB_EXTRA feature to HHKB/V-USB 2011-05-21 10:28:57 +09:00
tmk 068c31a7ba added initial V-USB support for HHKB 2011-05-16 00:14:06 +09:00
tmk 61e12a3157 move files: main_vusb.c ps2_usart.c sendchar_usart.c from ps2_usb to common dir 2011-05-07 00:48:18 +09:00
tmk a6b31e950f fix bug: send Fn key even after the layer is used. 2011-05-04 21:19:34 +09:00
tmk b0b6c33332 ad hoc fix for IDLE bug which affects on Mac only. 2011-05-04 13:42:34 +09:00
tmk 5de62e26a0 fix for ps2_usb Makefile and circuit 2011-05-04 08:16:26 +09:00
tmk 13e4662bae minor fix for HHKB Makefile and doc 2011-05-04 08:12:27 +09:00
tmk cec2549505 FIX: send last report when idle timeouts. (pjrc) 2011-03-10 11:17:54 +09:00
tmk 1a7c3585ed ADD: V-USB Circuit in README 2011-02-25 22:46:13 +09:00
tmk 258fd3c368 FIX: host_get_first_key in vusb/host.c 2011-02-25 21:58:00 +09:00
tmk 00350c180d v3.0 cleanse files 2011-02-22 03:49:02 +09:00
tmk d2b9489a5e fixed hhkb to comply new API. 2011-02-22 03:09:23 +09:00
tmk 60052acc0f fixed macway to comply new API. 2011-02-22 03:09:21 +09:00
tmk c958b2d19b fixed adb_usb to comply new API. 2011-02-22 03:09:18 +09:00
tmk fb8d23c60c integrate V-USB support into ps2_usb 2011-02-22 03:09:14 +09:00
tmk 47f5d8b545 Synchronous USART support for PS/2 on V-USB stack 2011-02-22 03:09:12 +09:00
tmk 239bdbf419 PS/2: request to resend when error is occured. 2011-02-22 03:09:09 +09:00
tmk 3015f191a5 fixed: not to send key if fn_keycode is modifier 2011-02-22 03:09:07 +09:00
tmk 9a938eecbd host interface for pjrc 2011-02-22 03:09:05 +09:00
tmk 2b8cd88ab1 refactor keyboard.h, host.h 2011-02-22 03:09:02 +09:00
tmk acc974c64b added protocol stack: pjrc, vusb 2011-02-22 03:08:59 +09:00
tmk 5552b5afea define sendcha() in usb_debug.c 2011-02-22 03:08:56 +09:00
tmk 04f351b802 PS/2 library receives data partially by interrupt 2011-02-22 03:08:54 +09:00
tmk 0632618d29 added initial support of mousekeys to ps2_vusb 2011-02-22 03:08:52 +09:00
tmk 4f5f1a53d4 added PS/2 to USB converter use V-USB as protocol stack 2011-02-22 03:08:49 +09:00
tmk c07408a447 Merge branch 'master' of github.com:tmk/tmk_keyboard 2011-02-22 03:06:00 +09:00
tmk cf95d8308f added some short keycode names for ISO and JIS keyboard. 2011-02-17 13:29:50 +09:00
tmk a96085faf6 added note about external pull resistor on DATA line. 2011-02-13 23:02:08 +09:00
tmk 5bc29b50ef fixed mousekey delay to do double/triple click easily. 2011-01-25 01:01:13 +09:00
tmk 23c686ad46 Exceptional handling for PS/2 scan code set 2
changed names which does not comply to C spec.(underscore prefix names)
2011-01-25 00:53:49 +09:00
tmk a28a2a6a5e rewrite code of layer switching 2011-01-23 04:19:17 +09:00
tmk bf1a37ba71 PS/2 to USB keyboard converter 2011-01-23 04:10:35 +09:00
tmk 7ad93f7850 added description of ADB socket pintouts. 2011-01-17 00:38:16 +09:00
tmk 849b10e921 changed wait time for volume control. 2011-01-17 00:37:36 +09:00
tmk 16be834617 changed special mode key for macway: Left Shift + Right Shift 2011-01-17 00:35:24 +09:00
tmk 06db39583f ADB keyboard LEDs support 2011-01-13 22:46:57 +09:00
tmk 40c24dc89a added 'Keymap' section to adb/README. 2011-01-13 17:56:13 +09:00
tmk c5b9f2b02b change keycodes and define keymap macro for AEK.
ADD: keymap macro for Apple Extended Keyboard in adb/keymap.c
FIX: keycodes for Keypad, Fn and Mousekey.
2011-01-13 16:39:49 +09:00
tmk 56e098d76e ADB to USB keyboard converter 2011-01-13 01:51:59 +09:00
tmk 1f5cd6d7dc FIX: error handling in ps2.c 2011-01-11 21:30:35 +09:00
tmk 035b286b24 added a file TODO. 2011-01-06 19:07:35 +09:00
tmk 3e56e80c7d changed signature of keymap_fn_layer() in keymap_skel.h.
FIX: name of mousekey macros usb_keycodes.h.
2011-01-06 15:37:14 +09:00
tmk fd49c69d1a added config option: MATRIX_HAS_GHOST and fixed some on matrix.c
ADD: Build option: MATRIX_HAS_GHOST to enable ghost blocking logic.
FIX: choose matrix buffer type(uint8_t/uint16_t) automatically
     depending on column size in matrix.c.
FIX: use uint8_t insted of int in matrix.c.
2011-01-06 15:33:08 +09:00
tmk 590235d4bc add "Build your own firmware" and "Features" section to README. 2011-01-06 15:11:37 +09:00
tmk 6b0c939d72 add a build option: USB_EXTRA_ENABLE 2011-01-05 00:19:43 +09:00
tmk 7272c65d3d add error handling to ps2_mouse 2011-01-04 20:30:23 +09:00
tmk 2a562a4191 Add PS/2 mouse support to connect TrackPoint Unit.
Change build options:  Makefile and config.h. See README.
2011-01-02 23:52:13 +09:00
tmk 1ed336a064 change keyboard report descriptor for NKRO.
It uses 1byte for modifiers and 15bytes(120bits) for keys now.
2010-12-11 23:20:49 +09:00
tmk 51f17f0231 add build option: NKRO_ENABLE(remove: USB_12KRO) 2010-12-08 01:57:55 +09:00
tmk 66ece29b0e tuning layer switch timing. 2010-11-26 15:29:02 +09:00
tmk 37ced39ae2 add build option USB_12KRO. 2010-11-26 01:56:21 +09:00
tmk d6da554687 support 12KRO 2010-11-24 22:17:35 +09:00
tmk 9019c901dd add system controls(power down/wake up) from generic desktop page(HID) 2010-11-18 22:35:49 +09:00
tmk 02d955e9fe add audio controls from consumer page(HID) 2010-11-17 16:06:20 +09:00
tmk 8240e606d4 change hhkb/keymap 2010-11-16 14:56:06 +09:00
tmk 8fc6c265d1 Merge branch 'led' 2010-11-07 20:47:24 +09:00
tmk 2ca3ab18a2 output previous key state on TP1684 when scaning matrix. 2010-11-07 20:45:04 +09:00
tmk 74b3e591fc FIX: LED debug 2010-11-06 02:03:52 +09:00
tmk 89feab2301 repeating Fn key: press twice quickly to repeat. 2010-11-04 01:08:24 +09:00
tmk a31b31e717 revise Fn key processing. 2010-11-03 17:33:20 +09:00
tmk 45d4a7a898 improve layer switching 2010-10-30 01:16:47 +09:00
tmk 6c3b9a2ded ADD: macway/doc
FIX: keymap
2010-10-28 15:43:51 +09:00
140 changed files with 15689 additions and 2162 deletions

View File

@ -1,636 +1,35 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Following variables need to be set in <target>/Makefile:
# TARGET
# COMMON_DIR
# TARGET_DIR
# TARGET_SRC
# MCU
# F_CPU
# List C source files here. (C dependencies are automatically generated.)
SRC = tmk.c \
key_process.c \
usb_keyboard.c \
usb_mouse.c \
usb_debug.c \
usb.c \
jump_bootloader.c \
SRC += host.c \
keyboard.c \
command.c \
layer.c \
timer.c \
print.c \
util.c
SRC += $(TARGET_SRC)
# C source file search path
VPATH = $(TARGET_DIR):$(COMMON_DIR)
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Option modules
ifdef MOUSEKEY_ENABLE
SRC += mousekey.c
OPT_DEFS += -DMOUSEKEY_ENABLE
endif
ifdef PS2_MOUSE_ENABLE
SRC += ps2.c \
ps2_mouse.c
OPT_DEFS += -DPS2_MOUSE_ENABLE
endif
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = .
ifdef USB_EXTRA_ENABLE
OPT_DEFS += -DUSB_EXTRA_ENABLE
endif
ifdef USB_NKRO_ENABLE
OPT_DEFS += -DUSB_NKRO_ENABLE
endif
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = $(TARGET_DIR) $(COMMON_DIR)
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL
CDEFS += -DDESCRIPTION=$(DESCRIPTION)
CDEFS += -DVENDOR_ID=$(VENDOR_ID)
CDEFS += -DPRODUCT_ID=$(PRODUCT_ID)
CDEFS += -DMANUFACTURER=$(MANUFACTURER)
CDEFS += -DPRODUCT=$(PRODUCT)
ifdef MOUSE_DELAY_TIME
CDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
OPT_DEFS += -DUSB_MOUSE_ENABLE
endif
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
ADEFS += -DDESCRIPTION=$(DESCRIPTION)
ADEFS += -DVENDOR_ID=$(VENDOR_ID)
ADEFS += -DPRODUCT_ID=$(PRODUCT_ID)
ADEFS += -DMANUFACTURER=$(MANUFACTURER)
ADEFS += -DPRODUCT=$(PRODUCT)
ifdef MOUSE_DELAY_TIME
ADEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
endif
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL -DDESCRIPTION=$(DESCRIPTION) -DVENDOR_ID=$(VENDOR_ID) -DPRODUCT_ID=$(PRODUCT_ID)
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
CPPDEFS += -DDESCRIPTION=$(DESCRIPTION)
CPPDEFS += -DVENDOR_ID=$(VENDOR_ID)
CPPDEFS += -DPRODUCT_ID=$(PRODUCT_ID)
CPPDEFS += -DMANUFACTURER=$(MANUFACTURER)
CPPDEFS += -DPRODUCT=$(PRODUCT)
ifdef MOUSE_DELAY_TIME
CPPDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
endif
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(@:%.o=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Programming Options (avrdude) ----------------
# Programming hardware
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = stk500v2
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = com1 # programmer connected to serial device
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
ELFSIZE = $(SIZE) $(TARGET).elf
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -z $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list end
clean_list :
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVEDIR) .dep
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config
include $(COMMON_DIR)/Makefile.rules

21
Makefile.pjrc Normal file
View File

@ -0,0 +1,21 @@
OPT_DEFS += -DHOST_PJRC
SRC = usb_keyboard.c \
usb_debug.c \
usb.c \
jump_bootloader.c
SRC += $(TARGET_SRC)
# C source file search path
VPATH = $(TARGET_DIR):$(COMMON_DIR):$(COMMON_DIR)/pjrc
# Option modules
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
SRC += usb_mouse.c
endif
ifdef USB_EXTRA_ENABLE
SRC += usb_extra.c
endif

547
Makefile.rules Normal file
View File

@ -0,0 +1,547 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = obj_$(TARGET)
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = $(subst :, ,$(VPATH))
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL
CDEFS += $(OPT_DEFS)
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
ADEFS += $(OPT_DEFS)
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
CPPDEFS += $(OPT_DEFS)
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(@:%.o=%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
CFLAGS += -include $(CONFIG_H)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(@:%.o=%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
CPPFLAGS += -include $(CONFIG_H)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(@:%.o=%.lst),-gstabs,--listing-cont-lines=100
ASFLAGS += -include $(CONFIG_H)
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
#
# Comennt out "--relax" option to avoid a error such:
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
#
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
REMOVE = rm -f
REMOVEDIR = rmdir
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC))))
# Define all listing files.
LST = $(patsubst %.c,$(OBJDIR)/%.lst,$(patsubst %.cpp,$(OBJDIR)/%.lst,$(patsubst %.S,$(OBJDIR)/%.lst,$(SRC))))
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
ELFSIZE = $(SIZE) $(TARGET).elf
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(PROGRAM_CMD)
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -z $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list end
clean_list :
@echo
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(OBJ)
$(REMOVE) $(LST)
$(REMOVE) $(OBJ:.o=.s)
$(REMOVE) $(OBJ:.o=.i)
$(REMOVE) -r .dep
$(REMOVEDIR) $(OBJDIR)
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config

11
Makefile.vusb Normal file
View File

@ -0,0 +1,11 @@
OPT_DEFS += -DHOST_VUSB
SRC = usbdrv.c \
usbdrvasm.S \
oddebug.c \
sendchar_usart.c
SRC += $(TARGET_SRC)
# C source file search path
VPATH = $(TARGET_DIR):$(COMMON_DIR):$(COMMON_DIR)/vusb:$(COMMON_DIR)/vusb/usbdrv

194
README
View File

@ -1,63 +1,128 @@
t.m.k. Keyboard Firmware
========================
This is keyboard firmware for Teensy(AVR USB MCU) and V-USB board.
source code repository:
http://github.com/tmk/tmk_keyboard
This is keyboard firmware for PFU HHKB style keyboard and Teensy/Teensy++ 2.0.
OS see this as composite device which has keyboard and mouse.
This firmware is used in following projects:
HHKB mod: http://geekhack.org/showwiki.php?title=Island:12047
Macway mod: http://geekhack.org/showwiki.php?title=Island:11930
PS2 to USB: http://geekhack.org/showwiki.php?title=Island:14618
ADB to USB: http://geekhack.org/showwiki.php?title=Island:14290
The project is heavily based on PJRC USB Keyboard/Mouse Example and
owes a debt to preceding keyboard firmware projects.
http://www.pjrc.com/teensy
Version
-------
0.1 2010/08/23
It works as normal keyboard.
It is for modified Macway keyboard(TP-999KB-E).
Features
--------
Mouse key
control mouse cursor from keyboard.
System Control Key
Power Down, Sleep, Wake Up & USB Remote Wake up
Media Control Key
Volume Down/Up, Mute
USB NKRO
send 120 keys(+ 8 modifiers) at most simultaneously.
PS/2 mouse support
integrate PS/2 mouse(TrackPoint) into keyboard as composite device.
1.0 2010/10/02
keyboard has mouse key now.
keyboard with layers.(see keymap.c)
FN_1(right cmd):
vi style layer
FN_2(next to right shift):
HHKB style layer
FN_3(left bottom):
h j k l: mouse move
a s d spc: mouse buttons
m ,: mouse wheel
1.1 2010/10/08
Matrix wiring changed for casing.
(and my Teensy PD3 seems to be latchuped and unusable. :<)
Limitations
-----------
1.2 2010/10/13
HHKB support
horizontal mouse wheel support
change keymaps
2.0 2010/10/27
HHKB/Macway support merged
Files & Directories
-------------------
Target:
hhkb/ keyboard controller for PFU HHKB pro
macway/ keyboard controller for Macway mod
ps2_usb/ PS2 to USB keyboard converter
adb_usb/ ADB to USB keyboard converter
USB Protocol Stack:
pjrc/ PJRC USB stack
vusb/ V-USB USB stack
ps2.[ch] PS/2 protocol
adb.[ch] ADB protocol
Build
-----
Compiling sources need AVR GCC, AVR Libc and GNU make.(You can use WinAVR on Windows.)
To compile needs AVR GCC, AVR Libc and GNU make.
You can use WinAVR on Windows. http://winavr.sourceforge.net/
$ cd <target> (hhkb or macway)
$ cd <target>
$ make
The firmware will be compiled as a file tmk_<target>.hex.
Debuging
--------
Debug print is on if 4 keys are pressed during booting.
Build your own firmware
-----------------------
Copying exsistent target(macway) is easy way.
1. Copy contens of macway/ to your own target directory.
2. Edit Makefile. See next section.
3. Edit config.h. See next section.
4. Edit matrix.c. You will need to fix followings at least.
matrix_init()
matrix_scan()
read_col()
unselect_rows()
select_row()
5. Edit keymap.c. NOTE: It is not final design and a bit messy.
You will need to fix followings at least.
KEYMAP
fn_layer[]
fn_keycode[]
keymaps[]
6. Build.
If you have a build error like following, comment out "--relax" option in Makefile.common.
(.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
Build Options
-------------
<target>/Makefile:
1. Set target name for your firmware.
TARGET = tmk_<target>
2. Choose a MCU and its frequency.
MCU = atmega32u4 # Teensy 2.0
#MCU = at90usb1286 # Teensy++ 2.0
F_CPU = 16000000
3. Choose optional modules as needed. Comment out to disable optional modules.
MOUSEKEY_ENABLE = yes # Mouse keys
PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
USB_EXTRA_ENABLE = yes # Enhanced feature for Windows(Audio control and System control)
USB_NKRO_ENABLE = yes # USB Nkey Rollover
<target>/config.h:
1. USB vendor/product ID and device description
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xBEEF
/* device description */
#define MANUFACTURER t.m.k.
#define PRODUCT Macway mod
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod
2. Keyboard matrix configuration
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
#define MATRIX_HAS_GHOST
3. Mouse keys configuration if needed.
4. PS/2 mouse configuration if needed.
Debuging & Rescue
-----------------
Use PJRC's hid_listen.exe to see debug messages.
Press <COMMAND> + H to debug menu.
(see config.h for <COMMAND> key combination.)
AVR Target board
----------------
Teensy/Teensy++
http://www.pjrc.com/teensy
Pressing any 3 keys when connected enables debug output.
Pressing any 4 keys when connected makes bootloader comes up.
Projects related
@ -83,59 +148,4 @@ ps2avr
http://sourceforge.net/projects/ps2avr/
TODO & ideas
------------
licensing notes(GPL)
I think GPL is not infringement of PJRC license.
souce code cleaning
sleep&wakeup
debouncing logic
will be coded when bouncing occurs.
bouncing doesnt occur on my ALPS switch so far.
scan rate is too slow?(to be measure)
layer switching
time before switching
timeout when not used during specific time
Trackpoint(PS/2)
receive PS/2 signal from TrackPoint
send USB HID report
Thinkpad keyboard support
turn keyboard to USB keyboard/mouse composite device
setting menu(configure without changing firmware)
console for display
keymap/layer setting
mouse speed/acceleration
matrix display
PS/2 keyboard mode
with USB to PS/2 dumb adapter(possible?)
AT90USBKEY support
and other AVR USB boards
DONE:
support for HHKB pro matrix signal
exchange controller board with teensy
2010/10/11
keymap
Matias half keyboard style
2010/10/23
souce code cleaning
2010/10/23
debug on/off
debug off by default
pressing keys during booting
2010/10/23
mouse horizontal wheel
http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
http://www.keil.com/forum/15671/
http://www.microsoft.com/whdc/device/input/wheel.mspx
2010/10/13
debug on/off
Fn key conbination during normal operation
matrix print on/off
key print on/off
mouse print on/off
2010/10/26
EOF

160
USB_NKRO.txt Normal file
View File

@ -0,0 +1,160 @@
USB NKRO MEMO
=============
2010/12/09
References
----------
USB - boot mode, NKRO, compatibility, etc...
http://geekhack.org/showthread.php?t=13162
NKey Rollover - Overview, Testing Methodology, and Results
http://geekhack.org/showwiki.php?title=NKey+Rollover+-+Overview+Testing+Methodology+and+Results
dfj's NKRO(2010/06)
http://geekhack.org/showpost.php?p=191195&postcount=251
http://geekhack.org/showthread.php?p=204389#post204389
Terminogy
---------
NKRO
ghost
matrix
mechanical with diodes
membrane
OS Support Status
-----------------
USB NKRO is possible *without* a custom driver.
At least following OSes supports.
Windows7 64bit
WindowsXP
Windows2000 SP4
Ubuntu10.4(Linux 2.6)
MacOSX(To be tested)
Custom Driver for USB NKRO
--------------------------
NOT NEEDED
at least when using fllowing report formats on Windows, Linux or MacOSX.
USB NKRO methods
----------------
1. Virtual keyboards
Keyboard can increase its KRO by using virtual keyboards with Standard or Extended report.
If the keyboard has 2 virtual keyboard with Standard report(6KRO), it gets 12KRO.
Using this method means the keyboard is a composite device.
2. Exteded report
It needs large report size for this method to achive NKRO.
If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient.
3. Bitmap report
If the keyboard has less than 128keys, 16byte report will be enough for NKRO.
The 16byte report seems to be reasonable cost to get NKRO.
Report Format
-------------
Other report formats than followings are possible, though these format are typical one.
1. Standard 8bytes
modifiers(bitmap) 1byte
reserved 1byte(not used)
keys(array) 1byte*6
Standard report can send 6keys plus 8modifiers simultaneously.
Standard report is used by most keyboards in the marketplace.
Standard report is identical to boot protocol report.
Standard report is hard to suffer from compatibility problems.
2. Extended standard 16,32,64bytes
modifiers(bitmap) 1byte
reserved 1byte(not used)
keys(array) 1byte*(14,32,62)
Extended report can send N-keys by using N+2bytes.
Extended report is expected to be compatible with boot protocol.
3. Bitmap 16,32,64bytes
keys(bitmap) (16,32)bytes
Bitmap report can send at most 128keys by 16bytes and 256keys by 32bytes.
Bitmap report can achieve USB NKRO efficiently in terms of report size.
Bitmap report needs a deliberation for boot protocol implementation.
Bitmap report descriptor sample:
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
// bitmap of modifiers
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
// LED output report
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute),
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant),
// bitmap of keys
0x95, (REPORT_BYTES-1)*8, // Report Count (),
0x75, 0x01, // Report Size (1),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum(1),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, (REPORT_BYTES-1)*8-1, // Usage Maximum (),
0x81, 0x02, // Input (Data, Variable, Absolute),
0xc0 // End Collection
where REPORT_BYTES is a report size in bytes.
Considerations
--------------
Compatibility
boot protocol
minor/old system
Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode.
This may cuase a problem on a keyboard which uses other report than Standard.
Reactivity
USB polling time
OS/Driver processing time
Windows Problem
---------------
1. Windows accepts only 6keys in case of Standard report.
It should be able to send 6keys plus 8modifiers.
2. Windows accepts only 10keys in case of 16bytes Extended report.
It should be able to send 14keys plus 8modifiers.
3. Windows accepts only 18keys in case of 32bytes Extended report.
It should be able to send 30keys plus 8modifiers.
If keys are pressed in excess of the number, wrong keys are registered on Windows.
This problem will be reportedly fixed soon.(2010/12/05)
http://forums.anandtech.com/showpost.php?p=30873364&postcount=17
Tools for testing NKRO
----------------------
Browser App:
http://www.microsoft.com/appliedsciences/content/projects/KeyboardGhostingDemo.aspx
http://random.xem.us/rollover.html
Windows:
AquaKeyTest.exe http://geekhack.org/showthread.php?t=6643
Linux:
xkeycaps
xev
showkeys
EOF

406
adb.c Normal file
View File

@ -0,0 +1,406 @@
/*
Copyright (c) 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 <util/delay.h>
#include <avr/io.h>
#include "adb.h"
static inline void data_lo(void);
static inline void data_hi(void);
static inline bool data_in(void);
#ifdef ADB_PSW_BIT
static inline void psw_lo(void);
static inline void psw_hi(void);
static inline bool psw_in(void);
#endif
static inline void attention(void);
static inline void place_bit0(void);
static inline void place_bit1(void);
static inline void send_byte(uint8_t data);
static inline bool read_bit(void);
static inline uint8_t read_byte(void);
static inline uint8_t wait_data_lo(uint8_t us);
static inline uint8_t wait_data_hi(uint8_t us);
void adb_host_init(void)
{
data_hi();
#ifdef ADB_PSW_BIT
psw_hi();
#endif
}
#ifdef ADB_PSW_BIT
bool adb_host_psw(void)
{
return psw_in();
}
#endif
uint16_t adb_host_kbd_recv(void)
{
uint16_t data = 0;
attention();
send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
place_bit0(); // Stopbit(0)
if (!wait_data_lo(0xFF)) // Tlt/Stop to Start(140-260us)
return 0; // No data to send
if (!read_bit()) // Startbit(1)
return -2;
data = read_byte();
data = (data<<8) | read_byte();
if (read_bit()) // Stopbit(0)
return -3;
return data;
}
// send state of LEDs
void adb_host_kbd_led(uint8_t led)
{
attention();
send_byte(0x2A); // Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
place_bit0(); // Stopbit(0)
_delay_us(200); // Tlt/Stop to Start
place_bit1(); // Startbit(1)
send_byte(0); // send upper byte (not used)
send_byte(led&0x07); // send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0: NumLock)
place_bit0(); // Stopbit(0);
}
static inline void data_lo()
{
ADB_DDR |= (1<<ADB_DATA_BIT);
ADB_PORT &= ~(1<<ADB_DATA_BIT);
}
static inline void data_hi()
{
ADB_PORT |= (1<<ADB_DATA_BIT);
ADB_DDR &= ~(1<<ADB_DATA_BIT);
}
static inline bool data_in()
{
ADB_PORT |= (1<<ADB_DATA_BIT);
ADB_DDR &= ~(1<<ADB_DATA_BIT);
return ADB_PIN&(1<<ADB_DATA_BIT);
}
#ifdef ADB_PSW_BIT
static inline void psw_lo()
{
ADB_DDR |= (1<<ADB_PSW_BIT);
ADB_PORT &= ~(1<<ADB_PSW_BIT);
}
static inline void psw_hi()
{
ADB_PORT |= (1<<ADB_PSW_BIT);
ADB_DDR &= ~(1<<ADB_PSW_BIT);
}
static inline bool psw_in()
{
ADB_PORT |= (1<<ADB_PSW_BIT);
ADB_DDR &= ~(1<<ADB_PSW_BIT);
return ADB_PIN&(1<<ADB_PSW_BIT);
}
#endif
static inline void attention(void)
{
data_lo();
_delay_us(700);
place_bit1();
}
static inline void place_bit0(void)
{
data_lo();
_delay_us(65);
data_hi();
_delay_us(35);
}
static inline void place_bit1(void)
{
data_lo();
_delay_us(35);
data_hi();
_delay_us(65);
}
static inline void send_byte(uint8_t data)
{
for (int i = 0; i < 8; i++) {
if (data&(0x80>>i))
place_bit1();
else
place_bit0();
}
}
static inline bool read_bit(void)
{
// ADB Bit Cells
//
// bit0: ______~~~
// 65 :35us
//
// bit1: ___~~~~~~
// 35 :65us
//
// bit0 low time: 60-70% of bit cell(42-91us)
// bit1 low time: 30-40% of bit cell(21-52us)
// bit cell time: 70-130us
// [from Apple IIgs Hardware Reference Second Edition]
//
// After 55us if data line is low/high then bit is 0/1.
// Too simple to rely on?
bool bit;
wait_data_lo(75); // wait the beginning of bit cell
_delay_us(55);
bit = data_in();
wait_data_hi(36); // wait high part of bit cell
return bit;
}
static inline uint8_t read_byte(void)
{
uint8_t data = 0;
for (int i = 0; i < 8; i++) {
data <<= 1;
if (read_bit())
data = data | 1;
}
return data;
}
static inline uint8_t wait_data_lo(uint8_t us)
{
while (data_in() && us) {
_delay_us(1);
us--;
}
return us;
}
static inline uint8_t wait_data_hi(uint8_t us)
{
while (!data_in() && us) {
_delay_us(1);
us--;
}
return us;
}
/*
ADB Protocol
============
Resources
---------
ADB - The Untold Story: Space Aliens Ate My Mouse
http://developer.apple.com/legacy/mac/library/#technotes/hw/hw_01.html
Apple IIgs Hardware Reference Second Edition [p80(Chapter6 p121)]
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIgs%20Hardware%20Reference.pdf
ADB Keycode
http://72.0.193.250/Documentation/macppc/adbkeycodes/
http://m0115.web.fc2.com/m0115.jpg
[Inside Macintosh volume V, pages 191-192]
ADB Signaling
http://kbdbabel.sourceforge.net/doc/kbd_signaling_pcxt_ps2_adb.pdf
ADB Overview & History
http://en.wikipedia.org/wiki/Apple_Desktop_Bus
Microchip Application Note: ADB device(with code for PIC16C)
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011062
AVR ATtiny2131 ADB to PS/2 converter(Japanese)
http://hp.vector.co.jp/authors/VA000177/html/KeyBoardA5DEA5CBA5A2II.html
Pinouts
-------
ADB female socket from the front:
__________
| | <--- top
| 4o o3 |
|2o o1|
| == |
|________| <--- bottom
| | <--- 4pins
ADB female socket from bottom:
========== <--- front
| |
| |
|2o o1|
|4o o3|
---------- <--- back
1: Data
2: Power SW(low when press Power key)
3: Vcc(5V)
4: GND
Commands
--------
ADB command is 1byte and consists of 4bit-address, 2bit-command
type and 2bit-register. The commands are always sent by Host.
Command format:
7 6 5 4 3 2 1 0
| | | |------------ address
| |-------- command type
| |---- register
bits commands
------------------------------------------------------
- - - - 0 0 0 0 Send Request(reset all devices)
A A A A 0 0 0 1 Flush(reset a device)
- - - - 0 0 1 0 Reserved
- - - - 0 0 1 1 Reserved
- - - - 0 1 - - Reserved
A A A A 1 0 R R Listen(write to a device)
A A A A 1 1 R R Talk(read from a device)
The command to read keycodes from keyboard is 0x2C which
consist of keyboard address 2 and Talk against register 0.
Address:
2: keyboard
3: mice
Registers:
0: application(keyobard uses this to store its data.)
1: application
2: application(keyboard uses this for LEDs and state of modifiers)
3: status and command
Communication
-------------
This is a minimum information for keyboard communication.
See "Resources" for detail.
Signaling:
~~~~____________~~||||||||||||__~~~~~_~~|||||||||||||||__~~~~
|800us | |7 Command 0| | | |15-64 Data 0|Stopbit(0)
+Attention | | | +Startbit(1)
+Startbit(1) | +Tlt(140-260us)
+stopbit(0)
Bit cells:
bit0: ______~~~
65 :35us
bit1: ___~~~~~~
35 :65us
bit0 low time: 60-70% of bit cell(42-91us)
bit1 low time: 30-40% of bit cell(21-52us)
bit cell time: 70-130us
[from Apple IIgs Hardware Reference Second Edition]
Criterion for bit0/1:
After 55us if line is low/high then bit is 0/1.
Attention & start bit:
Host asserts low in 560-1040us then places start bit(1).
Tlt(Stop to Start):
Bus stays high in 140-260us then device places start bit(1).
Global reset:
Host asserts low in 2.8-5.2ms. All devices are forced to reset.
Send request from device(Srq):
Device can request to send at commad(Global only?) stop bit.
keep low for 300us to request.
Keyboard Data(Register0)
This 16bit data can contains two keycodes and two released flags.
First keycode is palced in upper byte. When one keyocode is sent,
lower byte is 0xFF.
Release flag is 1 when key is released.
1514 . . . . . 8 7 6 . . . . . 0
| | | | | | | | | +-+-+-+-+-+-+- Keycode2
| | | | | | | | +--------------- Released2(1 when the key is released)
| +-+-+-+-+-+-+----------------- Keycode1
+------------------------------- Released1(1 when the key is released)
Keycodes:
Scancode consists of 7bit keycode and 1bit release flag.
Device can send two keycodes at once. If just one keycode is sent
keycode1 contains it and keyocode2 is 0xFF.
Power switch:
You can read the state from PSW line(active low) however
the switch has a special scancode 0x7F7F, so you can
also read from Data line. It uses 0xFFFF for release scancode.
Release code seems to delay about some 100ms. Due to Mac soft power?
Keyboard LEDs & state of keys(Register2)
This register hold current state of three LEDs and nine keys.
The state of LEDs can be changed by sending Listen command.
1514 . . . . . . 7 6 5 . 3 2 1 0
| | | | | | | | | | | | | | | +- LED1(NumLock)
| | | | | | | | | | | | | | +--- LED2(CapsLock)
| | | | | | | | | | | | | +----- LED3(ScrollLock)
| | | | | | | | | | +-+-+------- Reserved
| | | | | | | | | +------------- ScrollLock
| | | | | | | | +--------------- NumLock
| | | | | | | +----------------- Apple/Command
| | | | | | +------------------- Option
| | | | | +--------------------- Shift
| | | | +----------------------- Control
| | | +------------------------- Reset/Power
| | +--------------------------- CapsLock
| +----------------------------- Delete
+------------------------------- Reserved
END_OF_ADB
*/

19
adb.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef ADB_H
#define ADB_H
#include <stdbool.h>
#if !(defined(ADB_PORT) && \
defined(ADB_PIN) && \
defined(ADB_DDR) && \
defined(ADB_DATA_BIT))
# error "ADB port setting is required in config.h"
#endif
// ADB host
void adb_host_init(void);
bool adb_host_psw(void);
uint16_t adb_host_kbd_recv(void);
void adb_host_kbd_led(uint8_t led);
#endif

52
adb_usb/Makefile Normal file
View File

@ -0,0 +1,52 @@
# Target file name (without extension).
TARGET = adb_usb
# Directory common source filess exist
COMMON_DIR = ..
# Directory keyboard dependent files exist
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = main_pjrc.c \
keymap.c \
matrix.c \
led.c \
adb.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
USB_EXTRA_ENABLE = yes # Audio control and System control
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
include $(COMMON_DIR)/Makefile.pjrc
include $(COMMON_DIR)/Makefile.common

62
adb_usb/README Normal file
View File

@ -0,0 +1,62 @@
ADB to USB keyboard converter
=============================
http://geekhack.org/showwiki.php?title=Island:14290
This firmware converts ADB keyboard protocol to USB.
Build
-----
0. Connect ADB keyboard to Teensy by 3 lines(Vcc, GND, Data).
You need a external pull-up resistor on DATA line in most case,
in particular when you want to use a long or coiled cable.
This converter uses AVR's internal pull-up, but it seems to be too weak.
The external pull-up resistor is strongly recommended.
PSW line is optional. See ADB.txt for details.
1. Define following macros for ADB connection in config.h:
ADB_PORT
ADB_PIN
ADB_DDR
ADB_DATA_BIT
ADB_PSW_BIT
2. make
3. program Teensy.
Keymap
------
You can change a keymap by editing code of keymap.c like following.
This is a keymap for AEK, however, also used for other keyboards.
How to define the keymap is probably obvious. You can find key
symbols in usb_keycodes.h.
If you want to define some keymaps than just one, see hhkb/keymap.c and
macway/keymap.c as examples. Keymap(layer) switching may needs a bit of
effort at this time.
/* Default Layer: plain keymap
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,---.
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|
* `---' `---------------' `---------------' `---------------' `-----------' `---'
* ,-----------------------------------------------------------. ,-----------. ,---------------.
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| =| /| *|
* |-----------------------------------------------------------| |-----------| |---------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| -|
* |-----------------------------------------------------------| `-----------' |---------------|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| +|
* |-----------------------------------------------------------| ,---. |---------------|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
* |Ctrl |Gui |Alt | Space | | | | |Lef|Dow|Rig| | 0| .| |
* `-----------------------------------------------------------' `-----------' `---------------'
*/
KEYMAP(
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,EQL, PSLS,PAST,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, PMNS,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, LEFT,DOWN,RGHT, P0, PDOT,PENT
),
EOF

51
adb_usb/config.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef CONFIG_H
#define CONFIG_H
/* controller configuration */
#include "controller_teensy.h"
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x0ADB
#define MANUFACTURER t.m.k.
#define PRODUCT ADB keyboard converter
#define DESCRIPTION convert ADB keyboard to USB
/* matrix size */
#define MATRIX_ROWS 16 // keycode bit: 3-0
#define MATRIX_COLS 8 // keycode bit: 6-4
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (BIT_LSHIFT | BIT_LCTRL | BIT_LALT | BIT_LGUI) || \
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) \
)
/* mouse keys */
#ifdef MOUSEKEY_ENABLE
# define MOUSEKEY_DELAY_TIME 192
#endif
/* PS/2 mouse */
#ifdef PS2_MOUSE_ENABLE
# define PS2_CLOCK_PORT PORTF
# define PS2_CLOCK_PIN PINF
# define PS2_CLOCK_DDR DDRF
# define PS2_CLOCK_BIT 0
# define PS2_DATA_PORT PORTF
# define PS2_DATA_PIN PINF
# define PS2_DATA_DDR DDRF
# define PS2_DATA_BIT 1
#endif
/* ADB port setting */
#define ADB_PORT PORTF
#define ADB_PIN PINF
#define ADB_DDR DDRF
#define ADB_DATA_BIT 0
//#define ADB_PSW_BIT 1 // optional
#endif

133
adb_usb/keymap.c Normal file
View File

@ -0,0 +1,133 @@
/*
* 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.
/* Apple Extended Keyboard */
#define KEYMAP( \
K35, K7A,K78,K63,K76, K60,K61,K62,K64, K65,K6D,K67,K6F, K69,K6B,K71, K7F, \
K32,K12,K13,K14,K15,K17,K16,K1A,K1C,K19,K1D,K1B,K18,K33, K72,K73,K74, K47,K51,K4B,K43, \
K30,K0C,K0D,K0E,K0F,K11,K10,K20,K22,K1F,K23,K21,K1E,K2A, K75,K77,K79, K59,K5B,K5C,K4E, \
K39,K00,K01,K02,K03,K05,K04,K26,K28,K25,K29,K27, K24, K56,K57,K58,K45, \
K38,K06,K07,K08,K09,K0B,K2D,K2E,K2B,K2F,K2C, K7B, K3E, K53,K54,K55, \
K36,K3A,K37, K31, K3B,K3D,K3C, K52, K41,K4C \
) { \
{ 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_NO, KB_##K35, KB_##K36, KB_##K37 }, \
{ KB_##K38, KB_##K39, KB_##K3A, KB_##K3B, KB_##K3C, KB_##K3D, KB_##K3E, KB_NO }, \
{ KB_NO, KB_##K41, KB_NO, KB_##K43, KB_NO, KB_##K45, KB_NO, KB_##K47 }, \
{ KB_NO, KB_NO, KB_NO, KB_##K4B, KB_##K4C, KB_NO, KB_##K4E, KB_NO }, \
{ KB_NO, KB_##K51, KB_##K52, KB_##K53, KB_##K54, KB_##K55, KB_##K56, KB_##K57 }, \
{ KB_##K58, KB_##K59, KB_NO, KB_##K5B, KB_##K5C, KB_NO, KB_NO, KB_NO }, \
{ KB_##K60, KB_##K61, KB_##K62, KB_##K63, KB_##K64, KB_##K65, KB_NO, KB_##K67 }, \
{ KB_NO, KB_##K69, KB_NO, KB_##K6B, KB_NO, KB_##K6D, KB_NO, KB_##K6F }, \
{ KB_NO, KB_##K71, KB_##K72, KB_##K73, KB_##K74, KB_##K75, KB_##K76, KB_##K77 }, \
{ KB_##K78, KB_##K79, KB_##K7A, KB_##K7B, KB_NO, KB_NO, KB_NO, KB_##K7F } \
}
/* plain keymap
{
{ KB_A, KB_S, KB_D, KB_F, KB_H, KB_G, KB_Z, KB_X }, // 00-07
{ KB_C, KB_V, KB_NO, KB_B, KB_Q, KB_W, KB_E, KB_R }, // 08-0F
{ KB_Y, KB_T, KB_1, KB_2, KB_3, KB_4, KB_6, KB_5 }, // 10-17
{ KB_EQL, KB_9, KB_7, KB_MINS,KB_8, KB_0, KB_RBRC,KB_O }, // 18-1F
{ KB_U, KB_LBRC,KB_I, KB_P, KB_ENT, KB_L, KB_J, KB_QUOT}, // 20-27
{ KB_K, KB_SCLN,KB_BSLS,KB_COMM,KB_SLSH,KB_N, KB_M, KB_DOT }, // 28-2F
{ KB_TAB, KB_SPC, KB_GRV, KB_BSPC,KB_NO, KB_ESC, KB_LCTL,KB_LGUI}, // 30-37
{ KB_LSFT,KB_CAPS,KB_LALT,KB_LEFT,KB_RGHT,KB_DOWN,KB_UP, KB_NO }, // 38-3F
{ KB_NO, KB_PDOT,KB_NO, KB_PAST,KB_NO, KB_PPLS,KB_NO, KB_NLCK}, // 40-47
{ KB_NO, KB_NO, KB_NO, KB_PSLS,KB_PENT,KB_NO, KB_PMNS,KB_NO }, // 48-4F
{ KB_NO, KB_PEQL,KB_P0, KB_P1, KB_P2, KB_P3, KB_P4, KB_P5 }, // 50-57
{ KB_P6, KB_P7, KB_NO, KB_P8, KB_P9, KB_NO, KB_NO, KB_NO }, // 58-5F
{ KB_F5, KB_F6, KB_F7, KB_F3, KB_F8, KB_F9, KB_NO, KB_F11 }, // 60-67
{ KB_NO, KB_PSCR,KB_NO, KB_SLCK,KB_NO, KB_F10, KB_NO, KB_F12 }, // 68-6F
{ KB_NO, KB_BRK, KB_INS, KB_HOME,KB_PGUP,KB_DEL, KB_F4, KB_END }, // 70-77
{ KB_F2, KB_PGDN,KB_F1, KB_RSFT,KB_NO, KB_NO, KB_NO, KB_PWR }, // 78-7F
},
*/
// 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
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,---.
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|
* `---' `---------------' `---------------' `---------------' `-----------' `---'
* ,-----------------------------------------------------------. ,-----------. ,---------------.
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| =| /| *|
* |-----------------------------------------------------------| |-----------| |---------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| -|
* |-----------------------------------------------------------| `-----------' |---------------|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| +|
* |-----------------------------------------------------------| ,---. |---------------|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
* |Ctrl |Gui |Alt | Space | | | | |Lef|Dow|Rig| | 0| .| |
* `-----------------------------------------------------------' `-----------' `---------------'
*/
KEYMAP(
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,EQL, PSLS,PAST,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, PMNS,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, LEFT,DOWN,RGHT, P0, PDOT,PENT
),
};
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))]);
}

9
adb_usb/led.c Normal file
View File

@ -0,0 +1,9 @@
#include "stdint.h"
#include "adb.h"
#include "led.h"
void led_set(uint8_t usb_led)
{
adb_host_kbd_led(~usb_led);
}

193
adb_usb/matrix.c Normal file
View File

@ -0,0 +1,193 @@
/*
* 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 "adb.h"
#include "matrix.h"
#if (MATRIX_COLS > 16)
# error "MATRIX_COLS must not exceed 16"
#endif
#if (MATRIX_ROWS > 255)
# error "MATRIX_ROWS must not exceed 255"
#endif
static bool _matrix_is_modified = false;
// matrix state buffer(1:on, 0:off)
#if (MATRIX_COLS <= 8)
static uint8_t *matrix;
static uint8_t _matrix0[MATRIX_ROWS];
#else
static uint16_t *matrix;
static uint16_t _matrix0[MATRIX_ROWS];
#endif
#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)
{
adb_host_init();
// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
matrix = _matrix0;
print_enable = true;
debug_enable = true;
debug_matrix = true;
debug_keyboard = true;
debug_mouse = true;
print("debug enabled.\n");
return;
}
uint8_t matrix_scan(void)
{
uint16_t codes;
uint8_t key0, key1;
_matrix_is_modified = false;
codes = adb_host_kbd_recv();
key0 = codes>>8;
key1 = codes&0xFF;
if (codes == 0) { // no keys
return 0;
} else if (key0 == 0xFF && key1 != 0xFF) { // error
return codes&0xFF;
} else {
_matrix_is_modified = true;
_register_key(key0);
if (key1 != 0xFF) // key1 is 0xFF when no second key.
_register_key(key1);
}
if (debug_enable) {
print("adb_host_kbd_recv: "); phex16(codes); print("\n");
}
return 1;
}
bool matrix_is_modified(void)
{
return _matrix_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
#if (MATRIX_COLS <= 8)
uint8_t matrix_get_row(uint8_t row)
#else
uint16_t matrix_get_row(uint8_t row)
#endif
{
return matrix[row];
}
void matrix_print(void)
{
#if (MATRIX_COLS <= 8)
print("\nr/c 01234567\n");
#else
print("\nr/c 0123456789ABCDEF\n");
#endif
for (uint8_t row = 0; row < matrix_rows(); row++) {
phex(row); print(": ");
#if (MATRIX_COLS <= 8)
pbin_reverse(matrix_get_row(row));
#else
pbin_reverse16(matrix_get_row(row));
#endif
#ifdef MATRIX_HAS_GHOST
if (matrix_has_ghost_in_row(row)) {
print(" <ghost");
}
#endif
print("\n");
}
}
uint8_t matrix_key_count(void)
{
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
#if (MATRIX_COLS <= 8)
count += bitpop(matrix[i]);
#else
count += bitpop16(matrix[i]);
#endif
}
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)
{
uint8_t col, row;
col = key&0x07;
row = (key>>3)&0x0F;
if (key&0x80) {
matrix[row] &= ~(1<<col);
} else {
matrix[row] |= (1<<col);
}
}

211
command.c Normal file
View File

@ -0,0 +1,211 @@
#include <stdint.h>
#include <stdbool.h>
#include <util/delay.h>
#include "usb_keycodes.h"
#include "host.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "timer.h"
#include "layer.h"
#include "matrix.h"
#include "command.h"
#ifdef HOST_PJRC
# include "jump_bootloader.h"
# include "usb_keyboard.h"
# ifdef USB_EXTRA_ENABLE
# include "usb_extra.h"
# endif
#endif
static void help(void);
static uint8_t switch_layer(uint8_t layer);
uint8_t command_proc(void)
{
// check if we just want to swap from qwerty->dvorak and back
if(IS_SWAP()){
return switch_layer(current_layer > 0 ? 0 : 1);
}
if (!IS_COMMAND())
return 0;
uint8_t processed = 1;
bool last_print_enable = print_enable;
print_enable = true;
switch (host_get_first_key()) {
case KB_H:
help();
break;
case KB_B:
#ifdef HOST_PJRC
host_clear_keyboard_report();
host_send_keyboard_report();
print("jump to bootloader...\n");
_delay_ms(1000);
jump_bootloader(); // not return
#endif
break;
case KB_D:
debug_enable = !debug_enable;
if (debug_enable) {
last_print_enable = true;
print("debug enabled.\n");
debug_matrix = true;
debug_keyboard = true;
debug_mouse = true;
} else {
print("debug disabled.\n");
last_print_enable = false;
debug_matrix = false;
debug_keyboard = false;
debug_mouse = false;
}
break;
case KB_X: // debug matrix toggle
debug_matrix = !debug_matrix;
if (debug_matrix)
print("debug matrix enabled.\n");
else
print("debug matrix disabled.\n");
break;
case KB_K: // debug keyboard toggle
debug_keyboard = !debug_keyboard;
if (debug_keyboard)
print("debug keyboard enabled.\n");
else
print("debug keyboard disabled.\n");
break;
case KB_M: // debug mouse toggle
debug_mouse = !debug_mouse;
if (debug_mouse)
print("debug mouse enabled.\n");
else
print("debug mouse disabled.\n");
break;
case KB_V: // print version & information
print(STR(DESCRIPTION) "\n");
break;
case KB_T: // print timer
print("timer: "); phex16(timer_count); print("\n");
break;
case KB_P: // print toggle
if (last_print_enable) {
print("print disabled.\n");
last_print_enable = false;
} else {
last_print_enable = true;
print("print enabled.\n");
}
break;
case KB_S:
#ifdef HOST_PJRC
print("UDCON: "); phex(UDCON); print("\n");
print("UDIEN: "); phex(UDIEN); print("\n");
print("UDINT: "); phex(UDINT); print("\n");
print("usb_keyboard_leds:"); phex(usb_keyboard_leds); print("\n");
print("usb_keyboard_protocol: "); phex(usb_keyboard_protocol); print("\n");
print("usb_keyboard_idle_config:"); phex(usb_keyboard_idle_config); print("\n");
print("usb_keyboard_idle_count:"); phex(usb_keyboard_idle_count); print("\n");
#endif
break;
#ifdef USB_NKRO_ENABLE
case KB_N:
// send empty report before change
host_clear_keyboard_report();
host_send_keyboard_report();
keyboard_nkro = !keyboard_nkro;
if (keyboard_nkro)
print("USB_NKRO: enabled\n");
else
print("USB_NKRO: disabled\n");
break;
#endif
#ifdef USB_EXTRA_ENABLE
case KB_ESC:
#ifdef HOST_PJRC
if (suspend && remote_wakeup) {
usb_remote_wakeup();
} else {
host_system_send(SYSTEM_POWER_DOWN);
}
#else
host_system_send(SYSTEM_POWER_DOWN);
#endif
break;
#endif
case KB_BSPC:
matrix_init();
print("clear matrix\n");
break;
case KB_0:
return switch_layer(0);
case KB_1:
return switch_layer(1);
case KB_2:
return switch_layer(2);
case KB_3:
return switch_layer(3);
case KB_4:
return switch_layer(4);
case KB_5:
return switch_layer(5);
case KB_6:
return switch_layer(2);
default:
processed = 0;
}
//if (processed)
// _delay_ms(500);
print_enable = last_print_enable;
return processed;
}
static void help(void)
{
print("b: jump to bootloader\n");
print("d: toggle debug enable\n");
print("x: toggle matrix debug\n");
print("k: toggle keyboard debug\n");
print("m: toggle mouse debug\n");
print("p: toggle print enable\n");
print("v: print version\n");
print("t: print timer count\n");
print("s: print status\n");
#ifdef USB_NKRO_ENABLE
print("n: toggle USB_NKRO\n");
#endif
print("Backspace: clear matrix\n");
print("ESC: power down/wake up\n");
print("0: switch to Layer0 \n");
print("1: switch to Layer1 \n");
print("2: switch to Layer2 \n");
print("3: switch to Layer3 \n");
print("4: switch to Layer4 \n");
}
static uint8_t switch_layer(uint8_t layer)
{
print("current_layer: "); phex(current_layer); print("\n");
print("default_layer: "); phex(default_layer); print("\n");
uint8_t ret = 1;
if(layer == 0 && current_layer != 0){
DEBUG_LED_OFF;
ret = SCROLL_LOCK_TOGGLE;
//led_set(USB_LED_SCROLL_LOCK);
}
else if(current_layer == 0 && layer != 0){
DEBUG_LED_ON;
ret = SCROLL_LOCK_TOGGLE;
//led_set(USB_LED_SCROLL_LOCK);
}
current_layer = layer;
default_layer = layer;
print("switch to Layer: "); phex(layer); print("\n");
//_delay_ms(500); // now done in keyboard.c
return ret;
}

8
command.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef COMMAND_H
#define COMMAND
#define SCROLL_LOCK_TOGGLE 5
uint8_t command_proc(void);
#endif

View File

@ -2,7 +2,7 @@
#define TEENSY_H 1
// for Teensy/Teensy++ 2.0
#define DEBUG_LED 1
//#define DEBUG_LED 1
#define DEBUG_LED_CONFIG (DDRD |= (1<<6))
#define DEBUG_LED_ON (PORTD |= (1<<6))
#define DEBUG_LED_OFF (PORTD &= ~(1<<6))

View File

@ -6,7 +6,7 @@
#define debug(s) if(debug_enable) print(s)
#define debug_hex(c) if(debug_enable) phex(c)
#define debug_hex16(i) if(debug_enable) phex(i)
#define debug_hex16(i) if(debug_enable) phex16(i)
#define debug_bin(c) if(debug_enable) pbin(c)
#define debug_bin_reverse(c) if(debug_enable) pbin_reverse(c)

View File

@ -1,54 +1,10 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
# Makefile for PJRC Teensy
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
VENDOR_ID = 0xFEED
PRODUCT_ID = 0xCAFE
MANUFACTURER = 't.m.k.'
PRODUCT = 't.m.k. HHKB pro'
DESCRIPTION = 't.m.k. firmware for HHKB pro'
MOUSE_DELAY_TIME = 127
# Target file name (without extension).
TARGET = tmk_hhkb
TARGET = hhkb_pjrc
# Directory common source filess exist
COMMON_DIR = ..
@ -57,8 +13,12 @@ COMMON_DIR = ..
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = keymap.c \
matrix.c
TARGET_SRC = main_pjrc.c \
keymap.c \
matrix.c \
led.c
CONFIG_H = config_pjrc.h
# MCU name, you MUST set this to match the board you are using
@ -76,4 +36,20 @@ MCU = at90usb1286 # Teensy++ 2.0
# 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
USB_EXTRA_ENABLE = yes # Audio control and System control
USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
include $(COMMON_DIR)/Makefile.pjrc
include $(COMMON_DIR)/Makefile.common

84
hhkb/Makefile.vusb Normal file
View File

@ -0,0 +1,84 @@
#
# Makefile for V-USB
#
# Target file name (without extension).
TARGET = hhkb_vusb
# Directory common source filess exist
COMMON_DIR = ..
# Directory keyboard dependent files exist
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = main_vusb.c \
keymap.c \
matrix.c \
led.c
CONFIG_H = config_vusb.h
# V-USB debug level: To use ps2_usart.c level must be 0
# ps2_usart.c requires USART to receive PS/2 signal.
OPT_DEFS = -DDEBUG_LEVEL=0
# 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 = atmega168
# 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 = 20000000
# Build Options
# comment out to disable the options.
#
MOUSEKEY_ENABLE = yes # Mouse keys
USB_EXTRA_ENABLE = yes # Audio control and System control
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
AVRDUDE = avrdude
# Type: avrdude -c ? to get a full listing.
AVRDUDE_PROGRAMMER = usbasp
AVRDUDE_PORT =
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS = -p $(MCU) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
PROGRAM_CMD = $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
include $(COMMON_DIR)/Makefile.vusb
include $(COMMON_DIR)/Makefile.common

80
hhkb/README Normal file
View File

@ -0,0 +1,80 @@
Alternative Controller for HHKB
===============================
Feature
-------
- Mouse Keys
- NKRO on USB
- Keymap Layers
Customize Keymap
----------------
see keymap.c.
Build for Teensy
----------------
0. Edit matrix.c.
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts)
1. Define macros in config_pjrc.h.(Optional)
VENDOR_ID, PRODUCT_ID and string descriptor.
IS_COMMAND
2. Edit Makefile for MCU setting and build options.
MCU, F_CPU
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE
3. Build hex file.
$ make
4. Program MCU.
$ make program
Build for V-USB
---------------
0. Edit matrix.c and usbconfig.h.
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts)
define macros for V-USB in usbconfig.h.
1. Define macros in config_vusb.h.(Optional)
IS_COMMAND
2. Edit Makefile.vusb for MCU setting and build options.
MCU, F_CPU
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE
3. Build hex file.
$ make -f Makefile.vusb
4. Program MCU.
$ make -f Makefile.vusb program
Using a bootloader to program for convenience is recommended.
Once program this V-USB bootloader at first, you can program MCU without
extra programmer. You should have reset switch to start up as bootloader
mode in this case.
USBaspLoader:
http://www.obdev.at/products/vusb/usbasploader.html
V-USB Circuit
-------------
+---+ +---------------+
USB GND | | ATmega168 |
=== C3 | |
5V <-------+--------+---|Vcc,AVCC | HHKB
R1 | | ====
D- <----+--+-----R2-----|INT1 PB0-2|------->ROW
D+ <----|---+----R3-----|INT0 PB3-5|------->COL
Z1 Z2 | PB6|------->ENABLE
GND<----+---+--+--+-----|GND PE6|------->KEY
| | | PE7|------->PREV
| C2-+--|XTAL1 | (see doc/HHKB.txt for pinouts)
| X1 | |
+--C3-+--|XTAL2 RST|---SW--+GND
+---------------+
R1: 1.5K Ohm
R2,R3: 68 Ohm
Z1,Z2: Zener 3.6V
C1,C2: 22pF
C3: 0.1uF
X1: Crystal 20MHz(16MHz/12MHz)
SW: Push Switch(Optional for bootloader)
EOF

48
hhkb/config_pjrc.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef CONFIG_H
#define CONFIG_H
/* controller configuration */
#include "controller_teensy.h"
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xCAFE
#define MANUFACTURER t.m.k.
#define PRODUCT HHKB mod
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod
/* matrix size */
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
)
/* mouse keys */
#ifdef MOUSEKEY_ENABLE
# define MOUSEKEY_DELAY_TIME 192
#endif
/* PS/2 mouse */
#ifdef PS2_MOUSE_ENABLE
/*
# define PS2_CLOCK_PORT PORTF
# define PS2_CLOCK_PIN PINF
# define PS2_CLOCK_DDR DDRF
# define PS2_CLOCK_BIT 0
# define PS2_DATA_PORT PORTF
# define PS2_DATA_PIN PINF
# define PS2_DATA_DDR DDRF
# define PS2_DATA_BIT 1
*/
#endif
#endif

32
hhkb/config_vusb.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef CONFIG_H
#define CONFIG_H
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xC0FE
// TODO: share these strings with usbconfig.h
// Edit usbconfig.h to change these.
#define MANUFACTURER t.m.k.
#define PRODUCT HHKB mod
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod
/* matrix size */
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
)
/* mouse keys */
#ifdef MOUSEKEY_ENABLE
# define MOUSEKEY_DELAY_TIME 255
#endif
#endif

View File

@ -1,6 +0,0 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H 1
#include "controller_teensy.h"
#endif

View File

@ -8,7 +8,7 @@ Teensy++ has clean pinout and it makes programing and wiring easier.
This is just a proof of concept for replacing controller of HHKB, not a complete firmware.
My prototype firmware source tree is here:
branch: hhkb(http://github.com/tmk/tmk_keyboard/tree/hhkb)
github(http://github.com/tmk/tmk_keyboard)
This firmware is a port of my previous project:
HHKB style Mod(http://geekhack.org/showwiki.php?title=Island:11930)
PJRC:
@ -68,7 +68,7 @@ Keyswitch PCB:
http://www.alldatasheet.com/datasheet-pdf/pdf/27373/TI/SN74LS145D.html
BU9831 Non-volatile electronic potentiometer: for calibration?
http://www.alldatasheet.com/datasheet-pdf/pdf/36387/ROHM/BU9831.html
TP1684 Capacitive Sensing controller: no datasheet available.
TP1683/4 Capacitive Sensing controller: no datasheet available.
(HHKB_keyswitch.jpg)
@ -84,7 +84,7 @@ Two PCBs are connected by 15 lines. Vcc and GND use 3 lines each, other 9 lines
2 Vcc(5V)
3 Vcc(5V)
4 TP1684 KEY: Low(0) when key pressed PE6 input(with pullup)
5 TP1684 unknown:how to use PE7 input(with pullup)
5 TP1684 KEY_PREV: assert previous key state??? PE7 output
6 HC4051 A(bit0) select 8 rows(0 to 7) PB0 output
7 HC4051 B(bit1) PB1 output
8 HC4051 C(bit2) PB2 output
@ -120,16 +120,16 @@ Matrix diagram:
|bias control? - - - - - - - - ---
| 3.9K*8 R R R R R R R R |
+--------^+ +--------+ - - - - - - - - |
| TP 1684 | | HC4051 <0-------|-|-|-|-|-|-|-|--|R|-+
| 2| | HC4051 <0-------|-|-|-|-|-|-|-|--|R|-+
| |capa. | <1-------|-|-|-|-|-|-|-|--|R|-+
| |sense | <2-------|-|-|-|-|-|-|-|--|R|-+
| <------| <3-------|-|-|-|-|-|-|-|--|R|-+
| TP1684 |sense | <2-------|-|-|-|-|-|-|-|--|R|-+
| 11<------| <3-------|-|-|-|-|-|-|-|--|R|-+
| | | <4-------|-|-|-|-|-|-|-|--|R|-+
| | | <5-------|-|-|-|-|-|-|-|--|R|-+
| |calib.| <6-------|-|-|-|-|-|-|-|--|R|-+
| <-+? | <7-------|-|-|-|-|-|-|-|--|R|-+
+---V-----+ | +-^-^-^--+ 0 1 2 3 4 5 6 7 33K*8
KEY ??? | A B C +-----------------+
| <-+ | <6-------|-|-|-|-|-|-|-|--|R|-+
| 1 4 | | | <7-------|-|-|-|-|-|-|-|--|R|-+
+---V---^-+ | +-^-^-^--+ 0 1 2 3 4 5 6 7 33K*8
KEY PREV | A B C +-----------------+
| | +-^----+ | | | | LS145 |
Vcc | | |BU9831| | | | +-^--^--^--^------+
--- | | +------+ | | | A B C D +------+
@ -148,9 +148,11 @@ Signals charts:
(HHKB_chart1.jpg)
Space bar locate at ROW:3 COL:7. Key are selected by HC4051(C,B,A) and LS145(C,B,A).
Space bar locate at ROW:3 COL:7. A key is selected by HC4051(C,B,A) and LS145(C,B,A).
Key state can be read on TP1684(4/KEY) while asserting low on LS145(D).
Usage of TP1684(5) is unknown. Key state can be read without using this signal.
Usage of TP1684(5) is not clear. Controller seemed to output previous key state on this line.
However key state can be read without using this signal.
(HHKB_chart2.jpg)
@ -162,7 +164,13 @@ Matrix scan pseudo code:
for (col: 0-7) {
SELECT_COL(col); // set LS145(A,B,C)
_delay_us(50);
_delay_us(40);
if (prev_key_state(row, col)) {
KEY_PREV_ON;
}
_delay_us(7);
ENALBLE_COL(); // set LS145(D) to low
@ -173,13 +181,18 @@ Matrix scan pseudo code:
} else {
// not pressed
}
KEY_PREV_OFF;
UNALBLE_COL(); // set LS145(D) to high
_delay_us(150);
}
}
Keymap layers
-------------
Followings are added layers with additional Fn keys. They are not final decision.
Followings are added layers with additional Fn keys.
see keymap.c

0
hhkb/doc/HHKB_TP1684.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

0
hhkb/doc/HHKB_chart1.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

0
hhkb/doc/HHKB_chart2.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

0
hhkb/doc/HHKB_connector.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 189 KiB

0
hhkb/doc/HHKB_controller.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

0
hhkb/doc/HHKB_keyswitch.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

0
hhkb/doc/connector_contact.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 188 KiB

0
hhkb/doc/logic_analyzer.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

0
hhkb/doc/probe_contact.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 204 KiB

0
hhkb/doc/teensy_install.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

0
hhkb/doc/teensy_wiring.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

View File

@ -4,18 +4,16 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "usb_keyboard.h"
#include "host.h"
#include "usb_keycodes.h"
#include "matrix.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "keymap.h"
#define FN_KEYCODE(fn) (pgm_read_byte(&fn_keycode[(fn)]))
#define FN_LAYER(fn) (pgm_read_byte(&fn_layer[(fn)]))
#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.
#define KEYMAP( \
R3C1, R3C0, R0C0, R1C0, R1C1, R2C0, R2C1, R4C0, R4C1, R6C0, R6C1, R7C0, R7C1, R5C0, R5C1, \
R3C2, R0C1, R0C2, R1C3, R1C2, R2C3, R2C2, R4C2, R4C3, R6C2, R6C3, R7C3, R7C2, R5C2, \
@ -34,24 +32,32 @@
{ R7C0, R7C1, R7C2, R7C3, R7C4, R7C5, R7C6, KB_NO } \
}
static int current_layer = 0;
static bool layer_used = false;
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
/* layer to change into while Fn key pressed */
static const int PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 0, 0 };
// 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
1, // Fn1
2, // Fn2
3, // Fn3
4, // Fn4
0, // Fn5
0, // Fn6
0 // Fn7
};
/* keycode to sent when Fn key released without using layer keys. */
// 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, // FN_0 [NOT USED]
KB_NO, // FN_1 layer 1
KB_QUOTE, // FN_2 layer 2
KB_SCOLON, // FN_3 layer 3
KB_SPACE, // FN_4 layer 4 [NOT USED]
KB_NO, // FN_5 [NOT USED]
KB_NO, // FN_6 [NOT USED]
KB_NO // FN_7 [NOT USED]
KB_NO, // Fn0
KB_NO, // Fn1
KB_SLSH, // Fn2
KB_SCLN, // Fn3
KB_SPC, // Fn4
KB_NO, // Fn5
KB_NO, // Fn6
KB_NO // Fn7
};
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
@ -61,76 +67,76 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
* |-----------------------------------------------------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Backs|
* |-----------------------------------------------------------|
* |Contro| A| S| D| F| G| H| J| K| L|Fn3|Fn2|Return |
* |Contro| A| S| D| F| G| H| J| K| L|Fn3| '|Return |
* |-----------------------------------------------------------|
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn1|
* |Shift | Z| X| C| V| B| N| M| ,| .|Fn2|Shift |Fn1|
* `-----------------------------------------------------------'
* |Gui|Alt |Space |Alt |Gui|
* |Gui|Alt |Fn5 |Alt |Fn4|
* `-------------------------------------------'
*/
KEYMAP(KB_ESC, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9, KB_0, KB_MINS,KB_EQL, KB_BSLS,KB_GRV, \
KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC,KB_BSPC, \
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, FN_2, KB_ENT, \
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_SLSH,KB_RSFT,FN_1, \
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI),
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, KB_FN3, KB_QUOT,KB_ENT, \
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_FN2, KB_RSFT,KB_FN1, \
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI),
/* Layer 1: HHKB mode (HHKB Fn)
* ,-----------------------------------------------------------.
* |Pow| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |-----------------------------------------------------------|
* |Caps | | | | | | | |Psc|Slk|Pus|Up | |Backs|
* |-----------------------------------------------------------|
* |Contro| | | | | | *| /|Hom|PgU|Lef|Rig|Enter |
* |Contro|VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter |
* |-----------------------------------------------------------|
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
* `-----------------------------------------------------------'
* |Gui |Alt |Space |Alt |Gui|
* |Gui |Alt |Space |Alt |xxx|
* `--------------------------------------------'
*/
KEYMAP(KB_PWR, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \
KB_CAPS,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PSCR,KB_SLCK,KB_BRK, KB_UP, KB_NO, KB_BSPC, \
KB_LCTL,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_ASTR,KP_SLSH,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_PLUS,KP_MINS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,FN_1, \
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI),
KB_LCTL,KB_VOLD,KB_VOLU,KB_MUTE,KB_NO, KB_NO, KB_PAST,KB_PSLS,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PPLS,KB_PMNS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,KB_FN1, \
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_FN7),
/* Layer 2: Vi mode (Quote/Rmeta)
/* Layer 2: Vi mode (Slash)
* ,-----------------------------------------------------------.
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |-----------------------------------------------------------|
* |Tab |Hom|PgD|Up |PgU|End|Hom|PgD|PgUlEnd| | | |Backs|
* |-----------------------------------------------------------|
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| |xxx|Return |
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| | |Return |
* |-----------------------------------------------------------|
* |Shift | | | | | | | | | | |Shift | |
* |Shift | | | | | |Hom|PgD|PgUlEnd|xxx|Shift | |
* `-----------------------------------------------------------'
* |Gui|Alt |Space |Alt |Gui|
* `-------------------------------------------'
*/
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \
KB_TAB, KB_HOME,KB_PGDN,KB_UP, KB_PGUP,KB_END, KB_HOME,KB_PGDN,KB_PGUP,KB_END, KB_NO, KB_NO, KB_NO, KB_BSPC, \
KB_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, FN_2, KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
KB_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, KB_NO, KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_HOME,KB_PGDN,KB_PGUP,KB_END, KB_FN2, KB_RSFT,KB_NO, \
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI),
/* Layer 3: Mouse mode (Semicolon)
* ,-----------------------------------------------------------.
* |Esc| | | | | | | | | | | | | | |
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |-----------------------------------------------------------|
* |Tab |MwL|MwU|McU|MwD|MwL|MwR|MwD|MwU|MwR| | | |Backs|
* |Tab |MwL|MwU|McU|MwD|MwR|MwL|MwD|MwU|MwR| | | |Backs|
* |-----------------------------------------------------------|
* |Contro| |McL|McD|McR| |McL|McD|McU|McR|xxx| |Return |
* |-----------------------------------------------------------|
* |Shift | | | | | |Mb2|Mb1|Mb2|Mb3| |Shift | |
* |Shift |Mb4|Mb5|Mb1|Mb2|Mb3|Mb2|Mb1|Mb4|Mb5| |Shift | |
* `-----------------------------------------------------------'
* |Gui |Alt |Mb1 |Alt |Gui|
* `--------------------------------------------'
* Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel
*/
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \
KB_TAB, MS_WH_L,MS_WH_U,MS_UP, MS_WH_D,MS_WH_R,MS_WH_L,MS_WH_D,MS_WH_U,MS_WH_R,KB_NO, KB_NO, KB_NO, KB_BSPC, \
KB_LCTL,KB_NO, MS_LEFT,MS_DOWN,MS_RGHT,KB_NO, MS_LEFT,MS_DOWN,MS_UP, MS_RGHT,FN_3, KB_NO, KB_ENT, \
KB_LSFT,KB_NO, MS_DOWN,KB_NO, KB_NO, KB_NO, MS_BTN2,MS_BTN1,MS_BTN2,MS_BTN3,KB_NO, KB_RSFT,KB_NO, \
KB_LGUI,KB_LALT,MS_BTN1,KB_RALT,KB_RGUI),
KB_TAB, KB_WH_L,KB_WH_U,KB_MS_U,KB_WH_D,KB_WH_R,KB_WH_L,KB_WH_D,KB_WH_U,KB_WH_R,KB_NO, KB_NO, KB_NO, KB_BSPC, \
KB_LCTL,KB_NO, KB_MS_L,KB_MS_D,KB_MS_R,KB_NO, KB_MS_L,KB_MS_D,KB_MS_U,KB_MS_R,KB_FN3, KB_NO, KB_ENT, \
KB_LSFT,KB_BTN4,KB_BTN5,KB_BTN1,KB_BTN2,KB_BTN3,KB_BTN2,KB_BTN1,KB_BTN4,KB_BTN5,KB_NO, KB_RSFT,KB_NO, \
KB_LGUI,KB_LALT,KB_BTN1,KB_RALT,KB_RGUI),
/* Layer 4: Matias half keyboard style (Space)
* ,-----------------------------------------------------------.
@ -149,80 +155,21 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KB_BSPC,KB_P, KB_O, KB_I, KB_U, KB_Y, KB_T, KB_R, KB_E, KB_W, KB_Q, KB_NO, KB_NO, KB_TAB, \
KB_LCTL,KB_SCLN,KB_L, KB_K, KB_J, KB_H, KB_G, KB_F, KB_D, KB_S, KB_A, KB_RCTL,KB_RCTL, \
KB_LSFT,KB_SLSH,KB_DOT, KB_COMM,KB_M, KB_N, KB_B, KB_V, KB_C, KB_X, KB_Z, KB_RSFT,KB_NO, \
KB_LGUI,KB_LALT,FN_4, KB_RALT,KB_RGUI)
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI)
};
uint8_t keymap_get_keycode(int row, int col)
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
{
return keymap_get_keycodel(current_layer, row, col);
return KEYCODE(layer, row, col);
}
uint8_t keymap_get_keycodel(int layer, int row, int col)
uint8_t keymap_fn_layer(uint8_t fn_bits)
{
uint8_t code = KEYCODE(layer, row, col);
// normal key or mouse key
if (IS_KEY(code) || IS_MOUSE(code))
layer_used = true;
return code;
return pgm_read_byte(&fn_layer[biton(fn_bits)]);
}
inline
int keymap_get_layer(void)
uint8_t keymap_fn_keycode(uint8_t fn_bits)
{
return current_layer;
}
inline
int keymap_set_layer(int layer)
{
current_layer = layer;
return current_layer;
}
inline
bool keymap_is_special_mode(int fn_bits)
{
return (keyboard_modifier_keys == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI));
}
void keymap_fn_proc(int fn_bits)
{
// layer switching
static int last_bits = 0;
static uint8_t last_mod = 0;
if (usb_keyboard_has_key() || fn_bits == last_bits) {
// do nothing during press other than Fn key
return;
} else if (fn_bits == 0) {
// send key when Fn key is released without using the layer
if (!layer_used) {
uint8_t code = FN_KEYCODE(biton(last_bits));
if (code != KB_NO) {
if (IS_MOD(code)) {
keyboard_modifier_keys = last_mod | 1<<(code & 0x07);
} else {
keyboard_keys[0] = code;
keyboard_modifier_keys = last_mod;
}
usb_keyboard_send();
usb_keyboard_print();
usb_keyboard_clear();
}
}
last_bits = 0;
last_mod = 0;
layer_used = false;
keymap_set_layer(0); // default layer
} else if ((fn_bits & (fn_bits - 1)) == 0) {
// switch layer when just one Fn Key is pressed
last_bits = fn_bits;
last_mod = keyboard_modifier_keys;
layer_used = false;
keymap_set_layer(FN_LAYER(biton(fn_bits)));
debug("layer: "); phex(current_layer); debug("(");
debug_bin(last_bits); debug(")\n");
debug("last_mod: "); debug_hex(last_mod); debug("\n");
}
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
}

View File

@ -1,7 +0,0 @@
#ifndef KEYMAP_H
#define KEYMAP_H 1
#include "usb_keycodes.h"
#include "keymap_skel.h"
#endif

9
hhkb/led.c Normal file
View File

@ -0,0 +1,9 @@
#include "stdint.h"
#include "led.h"
/* HHKB has no LEDs */
void led_set(uint8_t usb_led)
{
}

View File

@ -4,65 +4,116 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "matrix.h"
#include "print.h"
#include "util.h"
#include "matrix.h"
// matrix is active low. (key on: 0/key off: 1)
//
// HHKB has no ghost and no bounce.
// row: HC4051 select input channel(0-8)
// PB0, PB1, PB2(A, B, C)
// col: LS145 select low output line(0-8)
// PB3, PB4, PB5, PB6(A, B, C, D)
// use D as ENABLE: (enable: 0/unenable: 1)
// key: KEY: (on: 0/ off:1)
// UNKNOWN: unknown whether input or output
// PE6,PE7(KEY, UNKNOWN)
#define COL_ENABLE (1<<6)
#define KEY_SELELCT(ROW, COL) (PORTB = COL_ENABLE|(((COL)&0x07)<<3)|((ROW)&0x07))
#define KEY_ENABLE (PORTB &= ~COL_ENABLE)
#define KEY_UNABLE (PORTB |= COL_ENABLE)
#define KEY_ON ((PINE&(1<<6)) ? false : true)
// matrix state buffer
uint8_t *matrix;
uint8_t *matrix_prev;
#if (MATRIX_COLS > 16)
# error "MATRIX_COLS must not exceed 16"
#endif
#if (MATRIX_ROWS > 255)
# error "MATRIX_ROWS must not exceed 255"
#endif
// matrix state buffer(1:on, 0:off)
#if (MATRIX_COLS <= 8)
static uint8_t *matrix;
static uint8_t *matrix_prev;
static uint8_t _matrix0[MATRIX_ROWS];
static uint8_t _matrix1[MATRIX_ROWS];
#else
static uint16_t *matrix;
static uint16_t *matrix_prev;
static uint16_t _matrix0[MATRIX_ROWS];
static uint16_t _matrix1[MATRIX_ROWS];
#endif
// HHKB has no ghost and no bounce.
#ifdef MATRIX_HAS_GHOST
static bool matrix_has_ghost_in_row(uint8_t row);
#endif
// Matrix I/O ports
//
// row: HC4051[A,B,C] selects scan row0-7
// col: LS145[A,B,C,D] selects scan col0-7 and enable(D)
// key: on: 0/off: 1
// prev: unknown: output previous key state(negated)?
#ifdef HOST_PJRC
// Ports for Teensy
// row: PB0-2
// col: PB3-5,6
// key: PE6(pull-uped)
// prev: PE7
#define KEY_INIT() do { \
DDRB |= 0x7F; \
DDRE |= (1<<7); \
DDRE &= ~(1<<6); \
PORTE |= (1<<6); \
} while (0)
#define KEY_SELECT(ROW, COL) (PORTB = (PORTB & 0xC0) | \
(((COL) & 0x07)<<3) | \
((ROW) & 0x07))
#define KEY_ENABLE() (PORTB &= ~(1<<6))
#define KEY_UNABLE() (PORTB |= (1<<6))
#define KEY_STATE() (PINE & (1<<6))
#define KEY_PREV_ON() (PORTE |= (1<<7))
#define KEY_PREV_OFF() (PORTE &= ~(1<<7))
#else
// Ports for V-USB
// key: PB0(pull-uped)
// prev: PB1
// row: PB2-4
// col: PC0-2,3
#define KEY_INIT() do { \
DDRB |= 0x1E; \
DDRB &= ~(1<<0); \
PORTB |= (1<<0); \
DDRC |= 0x0F; \
} while (0)
#define KEY_SELECT(ROW, COL) do { \
PORTB = (PORTB & 0xE3) | ((ROW) & 0x07)<<2; \
PORTC = (PORTC & 0xF8) | ((COL) & 0x07); \
} while (0)
#define KEY_ENABLE() (PORTC &= ~(1<<3))
#define KEY_UNABLE() (PORTC |= (1<<3))
#define KEY_STATE() (PINB & (1<<0))
#define KEY_PREV_ON() (PORTB |= (1<<1))
#define KEY_PREV_OFF() (PORTB &= ~(1<<1))
#endif
inline
int matrix_rows(void)
uint8_t matrix_rows(void)
{
return MATRIX_ROWS;
}
inline
int matrix_cols(void)
uint8_t matrix_cols(void)
{
return MATRIX_COLS;
}
// this must be called once before matrix_scan.
void matrix_init(void)
{
// row & col output(PB0-6)
DDRB = 0xFF;
PORTB = KEY_SELELCT(0, 0);
// KEY & VALID input with pullup(PE6,7)
DDRE = 0x3F;
PORTE = 0xC0;
KEY_INIT();
// initialize matrix state: all keys off
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
matrix = _matrix0;
matrix_prev = _matrix1;
}
int matrix_scan(void)
uint8_t matrix_scan(void)
{
uint8_t *tmp;
@ -70,18 +121,33 @@ int matrix_scan(void)
matrix_prev = matrix;
matrix = tmp;
for (int row = 0; row < MATRIX_ROWS; row++) {
for (int col = 0; col < MATRIX_COLS; col++) {
KEY_SELELCT(row, col);
_delay_us(50); // from logic analyzer chart
KEY_ENABLE;
_delay_us(10); // from logic analyzer chart
if (KEY_ON) {
matrix[row] |= (1<<col);
} else {
matrix[row] &= ~(1<<col);
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
KEY_SELECT(row, col);
_delay_us(40); // from logic analyzer chart
if (matrix_prev[row] & (1<<col)) {
KEY_PREV_ON();
}
KEY_UNABLE;
_delay_us(7); // from logic analyzer chart
#if HOST_VUSB
// to avoid V-USB interrupt during read key state
uint8_t sreg = SREG;
cli();
#endif
KEY_ENABLE();
_delay_us(10); // from logic analyzer chart
if (KEY_STATE()) {
matrix[row] &= ~(1<<col);
} else {
matrix[row] |= (1<<col);
}
#if HOST_VUSB
SREG = sreg;
#endif
KEY_PREV_OFF();
KEY_UNABLE();
_delay_us(150); // from logic analyzer chart
}
}
@ -90,7 +156,7 @@ int matrix_scan(void)
bool matrix_is_modified(void)
{
for (int i = 0; i < MATRIX_ROWS; i++) {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
if (matrix[i] != matrix_prev[i])
return true;
}
@ -100,36 +166,80 @@ bool matrix_is_modified(void)
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(int row, int col)
bool matrix_is_on(uint8_t row, uint8_t col)
{
return (matrix[row] & (1<<col));
}
inline
uint16_t matrix_get_row(int row)
#if (MATRIX_COLS <= 8)
uint8_t matrix_get_row(uint8_t row)
#else
uint16_t matrix_get_row(uint8_t row)
#endif
{
return matrix[row];
}
void matrix_print(void)
{
#if (MATRIX_COLS <= 8)
print("\nr/c 01234567\n");
for (int row = 0; row < matrix_rows(); row++) {
#else
print("\nr/c 0123456789ABCDEF\n");
#endif
for (uint8_t row = 0; row < matrix_rows(); row++) {
phex(row); print(": ");
#if (MATRIX_COLS <= 8)
pbin_reverse(matrix_get_row(row));
#else
pbin_reverse16(matrix_get_row(row));
#endif
#ifdef MATRIX_HAS_GHOST
if (matrix_has_ghost_in_row(row)) {
print(" <ghost");
}
#endif
print("\n");
}
}
int matrix_key_count(void)
uint8_t matrix_key_count(void)
{
int count = 0;
for (int i = 0; i < MATRIX_ROWS; i++) {
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
#if (MATRIX_COLS <= 8)
count += bitpop(matrix[i]);
#else
count += bitpop16(matrix[i]);
#endif
}
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

View File

@ -1,15 +0,0 @@
#ifndef MATRIX_H
#define MATRIX_H 1
#include <stdbool.h>
#include "matrix_skel.h"
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
extern uint8_t *matrix;
extern uint8_t *matrix_prev;
#endif

378
hhkb/usbconfig.h Normal file
View File

@ -0,0 +1,378 @@
/* Name: usbconfig.h
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2005-04-01
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $
*/
#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__
#include "config_vusb.h"
/*
General Description:
This file is an example configuration (with inline documentation) for the USB
driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is
also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may
wire the lines to any other port, as long as D+ is also wired to INT0 (or any
other hardware interrupt, as long as it is the highest level interrupt, see
section at the end of this file).
*/
/* ---------------------------- Hardware Config ---------------------------- */
#define USB_CFG_IOPORTNAME D
/* This is the port where the USB bus is connected. When you configure it to
* "B", the registers PORTB, PINB and DDRB will be used.
*/
#define USB_CFG_DMINUS_BIT 3
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
* This may be any bit in the port.
*/
#define USB_CFG_DPLUS_BIT 2
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
* This may be any bit in the port. Please note that D+ must also be connected
* to interrupt pin INT0! [You can also use other interrupts, see section
* "Optional MCU Description" below, or you can connect D- to the interrupt, as
* it is required if you use the USB_COUNT_SOF feature. If you use D- for the
* interrupt, the USB interrupt will also be triggered at Start-Of-Frame
* markers every millisecond.]
*/
#define USB_CFG_CLOCK_KHZ (F_CPU/1000)
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
* 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
* require no crystal, they tolerate +/- 1% deviation from the nominal
* frequency. All other rates require a precision of 2000 ppm and thus a
* crystal!
* Since F_CPU should be defined to your actual clock rate anyway, you should
* not need to modify this setting.
*/
#define USB_CFG_CHECK_CRC 0
/* Define this to 1 if you want that the driver checks integrity of incoming
* data packets (CRC checks). CRC checks cost quite a bit of code size and are
* currently only available for 18 MHz crystal clock. You must choose
* USB_CFG_CLOCK_KHZ = 18000 if you enable this option.
*/
/* ----------------------- Optional Hardware Config ------------------------ */
/* #define USB_CFG_PULLUP_IOPORTNAME D */
/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
* V+, you can connect and disconnect the device from firmware by calling
* the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
* This constant defines the port on which the pullup resistor is connected.
*/
/* #define USB_CFG_PULLUP_BIT 4 */
/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
* above) where the 1.5k pullup resistor is connected. See description
* above for details.
*/
/* --------------------------- Functional Range ---------------------------- */
#define USB_CFG_HAVE_INTRIN_ENDPOINT 1
/* Define this to 1 if you want to compile a version with two endpoints: The
* default control endpoint 0 and an interrupt-in endpoint (any other endpoint
* number).
*/
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1
/* Define this to 1 if you want to compile a version with three endpoints: The
* default control endpoint 0, an interrupt-in endpoint 3 (or the number
* configured below) and a catch-all default interrupt-in endpoint as above.
* You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
*/
#define USB_CFG_EP3_NUMBER 3
/* If the so-called endpoint 3 is used, it can now be configured to any other
* endpoint number (except 0) with this macro. Default if undefined is 3.
*/
/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */
/* The above macro defines the startup condition for data toggling on the
* interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1.
* Since the token is toggled BEFORE sending any data, the first packet is
* sent with the oposite value of this configuration!
*/
#define USB_CFG_IMPLEMENT_HALT 0
/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
* for endpoint 1 (interrupt endpoint). Although you may not need this feature,
* it is required by the standard. We have made it a config option because it
* bloats the code considerably.
*/
#define USB_CFG_SUPPRESS_INTR_CODE 0
/* Define this to 1 if you want to declare interrupt-in endpoints, but don't
* want to send any data over them. If this macro is defined to 1, functions
* usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if
* you need the interrupt-in endpoints in order to comply to an interface
* (e.g. HID), but never want to send any data. This option saves a couple
* of bytes in flash memory and the transmit buffers in RAM.
*/
#define USB_CFG_INTR_POLL_INTERVAL 10
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
* interval. The value is in milliseconds and must not be less than 10 ms for
* low speed devices.
*/
#define USB_CFG_IS_SELF_POWERED 0
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
* device is powered from the USB bus.
*/
#define USB_CFG_MAX_BUS_POWER 100
/* Set this variable to the maximum USB bus power consumption of your device.
* The value is in milliamperes. [It will be divided by two since USB
* communicates power requirements in units of 2 mA.]
*/
#define USB_CFG_IMPLEMENT_FN_WRITE 1
/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
* transfers. Set it to 0 if you don't need it and want to save a couple of
* bytes.
*/
#define USB_CFG_IMPLEMENT_FN_READ 0
/* Set this to 1 if you need to send control replies which are generated
* "on the fly" when usbFunctionRead() is called. If you only want to send
* data from a static buffer, set it to 0 and return the data from
* usbFunctionSetup(). This saves a couple of bytes.
*/
#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0
/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
* You must implement the function usbFunctionWriteOut() which receives all
* interrupt/bulk data sent to any endpoint other than 0. The endpoint number
* can be found in 'usbRxToken'.
*/
#define USB_CFG_HAVE_FLOWCONTROL 0
/* Define this to 1 if you want flowcontrol over USB data. See the definition
* of the macros usbDisableAllRequests() and usbEnableAllRequests() in
* usbdrv.h.
*/
#define USB_CFG_DRIVER_FLASH_PAGE 0
/* If the device has more than 64 kBytes of flash, define this to the 64 k page
* where the driver's constants (descriptors) are located. Or in other words:
* Define this to 1 for boot loaders on the ATMega128.
*/
#define USB_CFG_LONG_TRANSFERS 0
/* Define this to 1 if you want to send/receive blocks of more than 254 bytes
* in a single control-in or control-out transfer. Note that the capability
* for long transfers increases the driver size.
*/
/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
/* This macro is a hook if you want to do unconventional things. If it is
* defined, it's inserted at the beginning of received message processing.
* If you eat the received message and don't want default processing to
* proceed, do a return after doing your things. One possible application
* (besides debugging) is to flash a status LED on each packet.
*/
/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */
/* This macro is a hook if you need to know when an USB RESET occurs. It has
* one parameter which distinguishes between the start of RESET state and its
* end.
*/
/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */
/* This macro (if defined) is executed when a USB SET_ADDRESS request was
* received.
*/
#define USB_COUNT_SOF 0
/* define this macro to 1 if you need the global variable "usbSofCount" which
* counts SOF packets. This feature requires that the hardware interrupt is
* connected to D- instead of D+.
*/
/* #ifdef __ASSEMBLER__
* macro myAssemblerMacro
* in YL, TCNT0
* sts timer0Snapshot, YL
* endm
* #endif
* #define USB_SOF_HOOK myAssemblerMacro
* This macro (if defined) is executed in the assembler module when a
* Start Of Frame condition is detected. It is recommended to define it to
* the name of an assembler macro which is defined here as well so that more
* than one assembler instruction can be used. The macro may use the register
* YL and modify SREG. If it lasts longer than a couple of cycles, USB messages
* immediately after an SOF pulse may be lost and must be retried by the host.
* What can you do with this hook? Since the SOF signal occurs exactly every
* 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in
* designs running on the internal RC oscillator.
* Please note that Start Of Frame detection works only if D- is wired to the
* interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES!
*/
#define USB_CFG_CHECK_DATA_TOGGLING 0
/* define this macro to 1 if you want to filter out duplicate data packets
* sent by the host. Duplicates occur only as a consequence of communication
* errors, when the host does not receive an ACK. Please note that you need to
* implement the filtering yourself in usbFunctionWriteOut() and
* usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable
* for each control- and out-endpoint to check for duplicate packets.
*/
#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0
/* define this macro to 1 if you want the function usbMeasureFrameLength()
* compiled in. This function can be used to calibrate the AVR's RC oscillator.
*/
#define USB_USE_FAST_CRC 0
/* The assembler module has two implementations for the CRC algorithm. One is
* faster, the other is smaller. This CRC routine is only used for transmitted
* messages where timing is not critical. The faster routine needs 31 cycles
* per byte while the smaller one needs 61 to 69 cycles. The faster routine
* may be worth the 32 bytes bigger code size if you transmit lots of data and
* run the AVR close to its limit.
*/
/* -------------------------- Device Description --------------------------- */
#define USB_CFG_VENDOR_ID (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF)
/* USB vendor ID for the device, low byte first. If you have registered your
* own Vendor ID, define it here. Otherwise you may use one of obdev's free
* shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_ID (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF)
/* This is the ID of the product, low byte first. It is interpreted in the
* scope of the vendor ID. If you have registered your own VID with usb.org
* or if you have licensed a PID from somebody else, define it here. Otherwise
* you may use one of obdev's free shared VID/PID pairs. See the file
* USB-IDs-for-free.txt for details!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_VERSION 0x00, 0x01
/* Version number of the device: Minor number first, then major number.
*/
#define USB_CFG_VENDOR_NAME 't', '.', 'm', '.', 'k', '.'
#define USB_CFG_VENDOR_NAME_LEN 6
/* These two values define the vendor name returned by the USB device. The name
* must be given as a list of characters under single quotes. The characters
* are interpreted as Unicode (UTF-16) entities.
* If you don't want a vendor name string, undefine these macros.
* ALWAYS define a vendor name containing your Internet domain name if you use
* obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
* details.
*/
#define USB_CFG_DEVICE_NAME 'H', 'H', 'K', 'B', ' ', 'm', 'o', 'd'
#define USB_CFG_DEVICE_NAME_LEN 8
/* Same as above for the device name. If you don't want a device name, undefine
* the macros. See the file USB-IDs-for-free.txt before you assign a name if
* you use a shared VID/PID.
*/
/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */
/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */
/* Same as above for the serial number. If you don't want a serial number,
* undefine the macros.
* It may be useful to provide the serial number through other means than at
* compile time. See the section about descriptor properties below for how
* to fine tune control over USB descriptors such as the string descriptor
* for the serial number.
*/
#define USB_CFG_DEVICE_CLASS 0
#define USB_CFG_DEVICE_SUBCLASS 0
/* See USB specification if you want to conform to an existing device class.
* Class 0xff is "vendor specific".
*/
#define USB_CFG_INTERFACE_CLASS 3 /* HID */
#define USB_CFG_INTERFACE_SUBCLASS 1 /* Boot */
#define USB_CFG_INTERFACE_PROTOCOL 1 /* Keyboard */
/* See USB specification if you want to conform to an existing device class or
* protocol. The following classes must be set at interface level:
* HID class is 3, no subclass and protocol required (but may be useful!)
* CDC class is 2, use subclass 2 and protocol 1 for ACM
*/
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0
/* Define this to the length of the HID report descriptor, if you implement
* an HID device. Otherwise don't define it or define it to 0.
* If you use this define, you must add a PROGMEM character array named
* "usbHidReportDescriptor" to your code which contains the report descriptor.
* Don't forget to keep the array and this define in sync!
*/
/* #define USB_PUBLIC static */
/* Use the define above if you #include usbdrv.c instead of linking against it.
* This technique saves a couple of bytes in flash memory.
*/
/* ------------------- Fine Control over USB Descriptors ------------------- */
/* If you don't want to use the driver's default USB descriptors, you can
* provide our own. These can be provided as (1) fixed length static data in
* flash memory, (2) fixed length static data in RAM or (3) dynamically at
* runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
* information about this function.
* Descriptor handling is configured through the descriptor's properties. If
* no properties are defined or if they are 0, the default descriptor is used.
* Possible properties are:
* + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
* at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is
* used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if
* you want RAM pointers.
* + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
* in static memory is in RAM, not in flash memory.
* + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
* the driver must know the descriptor's length. The descriptor itself is
* found at the address of a well known identifier (see below).
* List of static descriptor names (must be declared PROGMEM if in flash):
* char usbDescriptorDevice[];
* char usbDescriptorConfiguration[];
* char usbDescriptorHidReport[];
* char usbDescriptorString0[];
* int usbDescriptorStringVendor[];
* int usbDescriptorStringDevice[];
* int usbDescriptorStringSerialNumber[];
* Other descriptors can't be provided statically, they must be provided
* dynamically at runtime.
*
* Descriptor properties are or-ed or added together, e.g.:
* #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
*
* The following descriptors are defined:
* USB_CFG_DESCR_PROPS_DEVICE
* USB_CFG_DESCR_PROPS_CONFIGURATION
* USB_CFG_DESCR_PROPS_STRINGS
* USB_CFG_DESCR_PROPS_STRING_0
* USB_CFG_DESCR_PROPS_STRING_VENDOR
* USB_CFG_DESCR_PROPS_STRING_PRODUCT
* USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
* USB_CFG_DESCR_PROPS_HID
* USB_CFG_DESCR_PROPS_HID_REPORT
* USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
*
* Note about string descriptors: String descriptors are not just strings, they
* are Unicode strings prefixed with a 2 byte header. Example:
* int serialNumberDescriptor[] = {
* USB_STRING_DESCRIPTOR_HEADER(6),
* 'S', 'e', 'r', 'i', 'a', 'l'
* };
*/
#define USB_CFG_DESCR_PROPS_DEVICE 0
#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC
//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
#define USB_CFG_DESCR_PROPS_STRINGS 0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC
#define USB_CFG_DESCR_PROPS_HID 0
#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC
//#define USB_CFG_DESCR_PROPS_HID_REPORT 0
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
/* ----------------------- Optional MCU Description ------------------------ */
/* The following configurations have working defaults in usbdrv.h. You
* usually don't need to set them explicitly. Only if you want to run
* the driver on a device which is not yet supported or with a compiler
* which is not fully supported (such as IAR C) or if you use a differnt
* interrupt than INT0, you may have to define some of these.
*/
/* #define USB_INTR_CFG MCUCR */
/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */
/* #define USB_INTR_CFG_CLR 0 */
/* #define USB_INTR_ENABLE GIMSK */
/* #define USB_INTR_ENABLE_BIT INT0 */
/* #define USB_INTR_PENDING GIFR */
/* #define USB_INTR_PENDING_BIT INTF0 */
/* #define USB_INTR_VECTOR INT0_vect */
#endif /* __usbconfig_h_included__ */

116
host.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef HOST_H
#define HOST_H
#include <stdint.h>
/* report id */
#define REPORT_ID_MOUSE 1
#define REPORT_ID_SYSTEM 2
#define REPORT_ID_CONSUMER 3
/* keyboard Modifiers in boot protocol report */
#define BIT_LCTRL (1<<0)
#define BIT_LSHIFT (1<<1)
#define BIT_LALT (1<<2)
#define BIT_LGUI (1<<3)
#define BIT_RCTRL (1<<4)
#define BIT_RSHIFT (1<<5)
#define BIT_RALT (1<<6)
#define BIT_RGUI (1<<7)
#define BIT_LCTL BIT_LCTRL
#define BIT_RCTL BIT_RCTRL
#define BIT_LSFT BIT_LSHIFT
#define BIT_RSFT BIT_RSHIFT
/* mouse buttons */
#define MOUSE_BTN1 (1<<0)
#define MOUSE_BTN2 (1<<1)
#define MOUSE_BTN3 (1<<2)
#define MOUSE_BTN4 (1<<3)
#define MOUSE_BTN5 (1<<4)
// Consumer Page(0x0C)
#define AUDIO_MUTE 0x00E2
#define AUDIO_VOL_UP 0x00E9
#define AUDIO_VOL_DOWN 0x00EA
#define TRANSPORT_NEXT_TRACK 0x00B5
#define TRANSPORT_PREV_TRACK 0x00B6
#define TRANSPORT_STOP 0x00B7
#define TRANSPORT_PLAY_PAUSE 0x00CD
#define AL_CC_CONFIG 0x0183
#define AL_EMAIL 0x018A
#define AL_CALCULATOR 0x0192
#define AL_LOCAL_BROWSER 0x0194
#define AC_SEARCH 0x0221
#define AC_HOME 0x0223
#define AC_BACK 0x0224
#define AC_FORWARD 0x0225
#define AC_STOP 0x0226
#define AC_REFRESH 0x0227
#define AC_BOOKMARKS 0x022A
// Generic Desktop Page(0x01)
#define SYSTEM_POWER_DOWN 0x0081
#define SYSTEM_SLEEP 0x0082
#define SYSTEM_WAKE_UP 0x0083
#if defined(HOST_PJRC)
# include "usb.h"
# if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS
# define REPORT_KEYS KBD2_REPORT_KEYS
# else
# define REPORT_KEYS KBD_REPORT_KEYS
# endif
#elif defined(HOST_VUSB)
# define REPORT_KEYS 6
#endif
typedef struct {
uint8_t mods;
uint8_t rserved;
uint8_t keys[REPORT_KEYS];
} report_keyboard_t;
typedef struct {
uint8_t report_id;
uint8_t buttons;
int8_t x;
int8_t y;
int8_t v;
int8_t h;
} report_mouse_t;
#ifdef USB_NKRO_ENABLE
extern bool keyboard_nkro;
#endif
extern report_keyboard_t *keyboard_report;
extern report_keyboard_t *keyboard_report_prev;
uint8_t host_keyboard_leds(void);
/* keyboard report operations */
void host_add_key(uint8_t key);
void host_add_mod_bit(uint8_t mod);
void host_set_mods(uint8_t mods);
void host_add_code(uint8_t code);
void host_swap_keyboard_report(void);
void host_clear_keyboard_report(void);
uint8_t host_has_anykey(void);
uint8_t host_get_first_key(void);
void host_send_keyboard_report(void);
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
void host_mouse_send(report_mouse_t *report);
#endif
#ifdef USB_EXTRA_ENABLE
void host_system_send(uint16_t data);
void host_consumer_send(uint16_t data);
#endif
#endif

View File

@ -1,35 +0,0 @@
// this code from:
// http://www.pjrc.com/teensy/jump_to_bootloader.html
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void jump_bootloader(void) {
cli();
// disable watchdog, if enabled
// disable all peripherals
UDCON = 1;
USBCON = (1<<FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5);
#if defined(__AVR_AT90USB162__) // Teensy 1.0
DDRB = 0; DDRC = 0; DDRD = 0;
TIMSK0 = 0; TIMSK1 = 0;
asm volatile("jmp 0x1F00");
#elif defined(__AVR_ATmega32U4__) // Teensy 2.0
DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0;
ADCSRA = 0;
asm volatile("jmp 0x3F00");
#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0;
ADCSRA = 0;
asm volatile("jmp 0x7E00");
#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0;
ADCSRA = 0;
asm volatile("jmp 0xFE00");
#endif
}

View File

@ -1,200 +0,0 @@
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "usb_keyboard.h"
#include "usb_mouse.h"
#include "usb_keycodes.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "jump_bootloader.h"
#include "matrix_skel.h"
#include "keymap_skel.h"
#include "controller.h"
#include "key_process.h"
#define MOUSE_MOVE_UNIT 10
#define MOUSE_MOVE_ACCEL (mouse_repeat < 50 ? mouse_repeat/5 : 10)
#ifndef MOUSE_DELAY_TIME
# define MOUSE_DELAY_TIME 255
#endif
#define MOUSE_DELAY_MS (MOUSE_DELAY_TIME >> (mouse_repeat < 5 ? mouse_repeat : 4))
// TODO: refactoring
void proc_matrix(void) {
static int mouse_repeat = 0;
bool modified = false;
//bool has_ghost = false;
int key_index = 0;
uint8_t mouse_btn = 0;
int8_t mouse_x = 0;
int8_t mouse_y = 0;
int8_t mouse_vwheel = 0;
int8_t mouse_hwheel = 0;
int fn_bits = 0;
matrix_scan();
modified = matrix_is_modified();
if (modified) {
if (debug_matrix) matrix_print();
#ifdef DEBUG_LED
// LED flash for debug
DEBUG_LED_CONFIG;
DEBUG_LED_ON;
#endif
}
if (matrix_has_ghost()) {
// should send error?
debug("matrix has ghost!!\n");
return;
}
usb_keyboard_clear();
for (int row = 0; row < matrix_rows(); row++) {
for (int col = 0; col < matrix_cols(); col++) {
if (!matrix_is_on(row, col)) continue;
uint8_t code = keymap_get_keycode(row, col);
if (code == KB_NO) {
// do nothing
} else if (IS_MOD(code)) {
keyboard_modifier_keys |= MOD_BIT(code);
} else if (IS_MOUSE(code)) {
// mouse
if (code == MS_UP)
mouse_y -= MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
if (code == MS_DOWN)
mouse_y += MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
if (code == MS_LEFT)
mouse_x -= MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
if (code == MS_RIGHT)
mouse_x += MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
if (code == MS_BTN1) mouse_btn |= BIT_BTN1;
if (code == MS_BTN2) mouse_btn |= BIT_BTN2;
if (code == MS_BTN3) mouse_btn |= BIT_BTN3;
if (code == MS_BTN4) mouse_btn |= BIT_BTN4;
if (code == MS_BTN5) mouse_btn |= BIT_BTN5;
if (code == MS_WH_UP) mouse_vwheel += 1;
if (code == MS_WH_DOWN) mouse_vwheel -= 1;
if (code == MS_WH_LEFT) mouse_hwheel -= 1;
if (code == MS_WH_RIGHT) mouse_hwheel += 1;
} else if (IS_FN(code)) {
fn_bits |= FN_BIT(code);
} else {
// normal keys
if (key_index < 6)
keyboard_keys[key_index] = code;
key_index++;
}
}
}
keymap_fn_proc(fn_bits);
// when 4 left modifier keys down
if (keymap_is_special_mode(fn_bits)) {
switch (keyboard_keys[0]) {
case KB_B: // bootloader
usb_keyboard_clear();
usb_keyboard_send();
print_enable = true;
print("jump to bootloader...\n");
_delay_ms(1000);
jump_bootloader(); // not return
break;
case KB_D: // debug all toggle
usb_keyboard_clear();
usb_keyboard_send();
debug_enable = !debug_enable;
if (debug_enable) {
print("debug enabled.\n");
print_enable = true;
debug_matrix = true;
debug_keyboard = true;
debug_mouse = true;
} else {
print("debug disabled.\n");
print_enable = false;
debug_matrix = false;
debug_keyboard = false;
debug_mouse = false;
}
_delay_ms(1000);
break;
case KB_X: // debug matrix toggle
usb_keyboard_clear();
usb_keyboard_send();
debug_matrix = !debug_matrix;
if (debug_matrix)
print("debug matrix enabled.\n");
else
print("debug matrix disabled.\n");
_delay_ms(1000);
break;
case KB_K: // debug keyboard toggle
usb_keyboard_clear();
usb_keyboard_send();
debug_keyboard = !debug_keyboard;
if (debug_keyboard)
print("debug keyboard enabled.\n");
else
print("debug keyboard disabled.\n");
_delay_ms(1000);
break;
case KB_M: // debug mouse toggle
usb_keyboard_clear();
usb_keyboard_send();
debug_mouse = !debug_mouse;
if (debug_mouse)
print("debug mouse enabled.\n");
else
print("debug mouse disabled.\n");
_delay_ms(1000);
break;
case KB_V: // print version & information
usb_keyboard_clear();
usb_keyboard_send();
print(STR(DESCRIPTION) "\n");
_delay_ms(1000);
break;
}
}
// send mouse packet to host
if (mouse_x || mouse_y || mouse_vwheel || mouse_hwheel || mouse_btn != mouse_buttons) {
mouse_buttons = mouse_btn;
if (mouse_x && mouse_y)
usb_mouse_move(mouse_x*0.7, mouse_y*0.7, mouse_vwheel, mouse_hwheel);
else
usb_mouse_move(mouse_x, mouse_y, mouse_vwheel, mouse_hwheel);
usb_mouse_print(mouse_x, mouse_y, mouse_vwheel, mouse_hwheel);
// acceleration
_delay_ms(MOUSE_DELAY_MS);
mouse_repeat++;
} else {
mouse_repeat = 0;
}
// send key packet to host
if (modified) {
if (key_index > 6) {
//Rollover
}
usb_keyboard_send();
usb_keyboard_print();
#ifdef DEBUG_LED
// LED flash for debug
DEBUG_LED_CONFIG;
DEBUG_LED_OFF;
#endif
}
}

View File

@ -1,7 +0,0 @@
#ifndef KEY_PROCESS_H
#define KEY_PROCESS_H 1
void proc_matrix(void);
#endif

196
keyboard.c Normal file
View File

@ -0,0 +1,196 @@
#include "keyboard.h"
#include "host.h"
#include "layer.h"
#include "matrix.h"
#include "led.h"
#include "usb_keycodes.h"
#include "timer.h"
#include "print.h"
#include "debug.h"
#include "command.h"
#ifdef MOUSEKEY_ENABLE
#include "mousekey.h"
#endif
#ifdef USB_EXTRA_ENABLE
#include <util/delay.h>
#endif
static uint8_t last_leds = 0;
static bool scroll_lock = false;
void keyboard_init(void)
{
timer_init();
matrix_init();
#ifdef PS2_MOUSE_ENABLE
ps2_mouse_init();
#endif
}
void keyboard_proc(void)
{
uint8_t fn_bits = 0;
#ifdef USB_EXTRA_ENABLE
uint16_t consumer_code = 0;
#endif
matrix_scan();
if (matrix_is_modified()) {
if (debug_matrix) matrix_print();
#ifdef DEBUG_LED
// LED flash for debug
DEBUG_LED_CONFIG;
DEBUG_LED_ON;
#endif
}
if (matrix_has_ghost()) {
// should send error?
debug("matrix has ghost!!\n");
return;
}
host_swap_keyboard_report();
host_clear_keyboard_report();
for (int row = 0; row < matrix_rows(); row++) {
for (int col = 0; col < matrix_cols(); col++) {
if (!matrix_is_on(row, col)) continue;
//print("row,col: "); pdec(row); print(","); pdec(col); print("\n");
uint8_t code = layer_get_keycode(row, col);
//print("keycode: "); pdec(code); print("\n");
if (code == KB_NO) {
// do nothing
print("KB_NO: "); pdec(row); print(","); pdec(col); print("\n");
} else if (IS_MOD(code)) {
host_add_mod_bit(MOD_BIT(code));
} else if (IS_FN(code)) {
fn_bits |= FN_BIT(code);
}
#ifdef USB_EXTRA_ENABLE
// System Control
else if (code == KB_SYSTEM_POWER) {
#ifdef HOST_PJRC
if (suspend && remote_wakeup) {
usb_remote_wakeup();
} else {
host_system_send(SYSTEM_POWER_DOWN);
}
#else
host_system_send(SYSTEM_POWER_DOWN);
#endif
host_system_send(0);
_delay_ms(500);
} else if (code == KB_SYSTEM_SLEEP) {
host_system_send(SYSTEM_SLEEP);
host_system_send(0);
_delay_ms(500);
} else if (code == KB_SYSTEM_WAKE) {
host_system_send(SYSTEM_WAKE_UP);
host_system_send(0);
_delay_ms(500);
}
// Consumer Page
else if (code == KB_AUDIO_MUTE) {
consumer_code = AUDIO_MUTE;
} else if (code == KB_AUDIO_VOL_UP) {
consumer_code = AUDIO_VOL_UP;
} else if (code == KB_AUDIO_VOL_DOWN) {
consumer_code = AUDIO_VOL_DOWN;
}
else if (code == KB_MEDIA_NEXT_TRACK) {
consumer_code = TRANSPORT_NEXT_TRACK;
} else if (code == KB_MEDIA_PREV_TRACK) {
consumer_code = TRANSPORT_PREV_TRACK;
} else if (code == KB_MEDIA_STOP) {
consumer_code = TRANSPORT_STOP;
} else if (code == KB_MEDIA_PLAY_PAUSE) {
consumer_code = TRANSPORT_PLAY_PAUSE;
} else if (code == KB_MEDIA_SELECT) {
consumer_code = AL_CC_CONFIG;
}
else if (code == KB_MAIL) {
consumer_code = AL_EMAIL;
} else if (code == KB_CALCULATOR) {
consumer_code = AL_CALCULATOR;
} else if (code == KB_MY_COMPUTER) {
consumer_code = AL_LOCAL_BROWSER;
}
else if (code == KB_WWW_SEARCH) {
consumer_code = AC_SEARCH;
} else if (code == KB_WWW_HOME) {
consumer_code = AC_HOME;
} else if (code == KB_WWW_BACK) {
consumer_code = AC_BACK;
} else if (code == KB_WWW_FORWARD) {
consumer_code = AC_FORWARD;
} else if (code == KB_WWW_STOP) {
consumer_code = AC_STOP;
} else if (code == KB_WWW_REFRESH) {
consumer_code = AC_REFRESH;
} else if (code == KB_WWW_FAVORITES) {
consumer_code = AC_BOOKMARKS;
}
#endif
else if (IS_KEY(code)) {
host_add_key(code);
}
#ifdef MOUSEKEY_ENABLE
else if (IS_MOUSEKEY(code)) {
mousekey_decode(code);
}
#endif
else {
debug("ignore keycode: "); debug_hex(code); debug("\n");
}
}
}
layer_switching(fn_bits);
uint8_t ret = command_proc();
if (ret != 0 && ret != SCROLL_LOCK_TOGGLE) {
_delay_ms(500);
return;
}
if(ret == SCROLL_LOCK_TOGGLE){
scroll_lock = !scroll_lock;
}
// TODO: should send only when changed from last report
if (matrix_is_modified()) {
host_send_keyboard_report();
#ifdef USB_EXTRA_ENABLE
host_consumer_send(consumer_code);
#endif
#ifdef DEBUG_LED
// LED flash for debug
DEBUG_LED_CONFIG;
DEBUG_LED_OFF;
#endif
}
#ifdef MOUSEKEY_ENABLE
mousekey_send();
#endif
#ifdef PS2_MOUSE_ENABLE
// TODO: should comform new API
if (ps2_mouse_read() == 0)
ps2_mouse_usb_send();
#endif
uint8_t current_leds = (scroll_lock || IS_SHORTCUT()) ? (host_keyboard_leds() | (1<<USB_LED_SCROLL_LOCK)) : host_keyboard_leds();
if (last_leds != current_leds) {
keyboard_set_leds(current_leds);
last_leds = current_leds;
if(ret == SCROLL_LOCK_TOGGLE)
_delay_ms(500);
}
}
void keyboard_set_leds(uint8_t leds)
{
led_set(leds);
}

11
keyboard.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include <stdint.h>
void keyboard_init(void);
void keyboard_proc(void);
void keyboard_set_leds(uint8_t leds);
#endif

18
keymap.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef KEYMAP_H
#define KEYMAP_H
#include <stdint.h>
#include <stdbool.h>
#include "usb_keycodes.h"
/* keycode in specific layer */
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);
/* layer to move during press Fn key */
uint8_t keymap_fn_layer(uint8_t fn_bits);
/* keycode to send when release Fn key without using */
uint8_t keymap_fn_keycode(uint8_t fn_bits);
#endif

View File

@ -1,18 +0,0 @@
#ifndef KEYMAP_SKEL_H
#define KEYMAP_SKEL_H 1
#include <stdint.h>
#include <stdbool.h>
#include "usb_keycodes.h"
uint8_t keymap_get_keycode(int row, int col);
uint8_t keymap_get_keycodel(int layer, int row, int col);
int keymap_get_layer(void);
int keymap_set_layer(int layer);
bool keymap_is_special_mode(int fn_bits);
/* process Fn keys. This.should be called every scan. */
void keymap_fn_proc(int fn_bits);
#endif

183
layer.c Normal file
View File

@ -0,0 +1,183 @@
#include "keymap.h"
#include "host.h"
#include "debug.h"
#include "timer.h"
#include "layer.h"
/*
* Parameters:
* ENTER_DELAY |=======|
* SEND_FN_TERM |================|
*
* Fn key processing cases:
* 1. release Fn after SEND_FN_TERM.
* Layer sw ___________|~~~~~~~~~~~|___
* Fn press ___|~~~~~~~~~~~~~~~~~~~|___
* Fn send ___________________________
*
* 2. release Fn during SEND_FN_TERM.(not layer used)
* Layer sw ___________|~~~~~~|________
* Fn press ___|~~~~~~~~~~~~~~|________
* Fn key send __________________|~|______
* other key press ___________________________
* other key send ___________________________
*
* 3. release Fn during SEND_FN_TERM.(layer used)
* Layer sw ___________|~~~~~~|________
* Fn press ___|~~~~~~~~~~~~~~|________
* Fn key send ___________________________
* Fn send ___________________________
* other key press _____________|~~|__________
* other key send _____________|~~|__________
*
* 4. press other key during ENTER_DELAY.
* Layer sw ___________________________
* Fn key press ___|~~~~~~~~~|_____________
* Fn key send ______|~~~~~~|_____________
* other key press ______|~~~|________________
* other key send _______|~~|________________
*
* 5. press Fn while press other key.
* Layer sw ___________________________
* Fn key press ___|~~~~~~~~~|_____________
* Fn key send ___|~~~~~~~~~|_____________
* other key press ~~~~~~~|___________________
* other key send ~~~~~~~|___________________
*
* 6. press Fn twice quickly and keep holding down.(repeat)
* Layer sw ___________________________
* Fn key press ___|~|____|~~~~~~~~~~~~~~~~
* Fn key send _____|~|__|~~~~~~~~~~~~~~~~
*/
// LAYER_ENTER_DELAY: prevent from moving new layer
#define LAYER_ENTER_DELAY 5
// LAYER_SEND_FN_TERM: send keycode if release key in this term
#define LAYER_SEND_FN_TERM 40
uint8_t default_layer = 0;
uint8_t current_layer = 0;
static bool layer_used = false;
static uint8_t new_layer(uint8_t fn_bits);
uint8_t layer_get_keycode(uint8_t row, uint8_t col)
{
uint8_t code = keymap_get_keycode(IS_SHORTCUT() ? SHORTCUT_LAYOUT : current_layer, row, col);
// normal key or mouse key
if ((IS_KEY(code) || IS_MOUSEKEY(code))) {
layer_used = true;
}
return code;
}
// bit substract b from a
#define BIT_SUBST(a, b) (a&(a^b))
void layer_switching(uint8_t fn_bits)
{
// layer switching
static uint8_t last_fn = 0;
static uint8_t last_mods = 0;
static uint16_t last_timer = 0;
static uint8_t sent_fn = 0;
if (fn_bits == last_fn) { // Fn state is not changed
if (fn_bits == 0) {
// do nothing
} else {
if (timer_elapsed(last_timer) > LAYER_ENTER_DELAY) {
uint8_t _layer_to_switch = new_layer(BIT_SUBST(fn_bits, sent_fn));
if (current_layer != _layer_to_switch) { // not switch layer yet
debug("Fn case: 1,2,3(LAYER_ENTER_DELAY passed)\n");
debug("Switch Layer: "); debug_hex(current_layer);
current_layer = _layer_to_switch;
layer_used = false;
debug(" -> "); debug_hex(current_layer); debug("\n");
}
} else {
if (host_has_anykey()) { // other keys is pressed
uint8_t _fn_to_send = BIT_SUBST(fn_bits, sent_fn);
if (_fn_to_send) {
debug("Fn case: 4(send Fn before other key pressed)\n");
// send only Fn key first
host_swap_keyboard_report();
host_clear_keyboard_report();
host_set_mods(last_mods);
host_add_code(keymap_fn_keycode(_fn_to_send)); // TODO: do all Fn keys
host_send_keyboard_report();
host_swap_keyboard_report();
sent_fn |= _fn_to_send;
}
}
}
// add Fn keys to send
//host_add_code(keymap_fn_keycode(fn_bits&sent_fn)); // TODO: do all Fn keys
}
} else { // Fn state is changed(edge)
uint8_t fn_changed = 0;
debug("fn_bits: "); debug_bin(fn_bits); debug("\n");
debug("sent_fn: "); debug_bin(sent_fn); debug("\n");
debug("last_fn: "); debug_bin(last_fn); debug("\n");
debug("last_mods: "); debug_hex(last_mods); debug("\n");
debug("last_timer: "); debug_hex16(last_timer); debug("\n");
// pressed Fn
if ((fn_changed = BIT_SUBST(fn_bits, last_fn))) {
debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
if (host_has_anykey()) {
debug("Fn case: 5(pressed Fn with other key)\n");
sent_fn |= fn_changed;
} else if (fn_changed & sent_fn) { // pressed same Fn in a row
if (timer_elapsed(last_timer) > LAYER_ENTER_DELAY) {
debug("Fn case: 6(not repeat)\n");
// time passed: not repeate
sent_fn &= ~fn_changed;
} else {
debug("Fn case: 6(repeat)\n");
}
}
}
// released Fn
if ((fn_changed = BIT_SUBST(last_fn, fn_bits))) {
debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
if (timer_elapsed(last_timer) < LAYER_SEND_FN_TERM) {
if (!layer_used && BIT_SUBST(fn_changed, sent_fn)) {
debug("Fn case: 2(send Fn one shot: released Fn during LAYER_SEND_FN_TERM)\n");
// send only Fn key first
host_swap_keyboard_report();
host_clear_keyboard_report();
host_set_mods(last_mods);
host_add_code(keymap_fn_keycode(fn_changed)); // TODO: do all Fn keys
host_send_keyboard_report();
host_swap_keyboard_report();
sent_fn |= fn_changed;
}
}
debug("Switch Layer(released Fn): "); debug_hex(current_layer);
current_layer = new_layer(BIT_SUBST(fn_bits, sent_fn));
debug(" -> "); debug_hex(current_layer); debug("\n");
}
layer_used = false;
last_fn = fn_bits;
last_mods = keyboard_report->mods;
last_timer = timer_read();
}
// send Fn keys
for (uint8_t i = 0; i < 8; i++) {
if ((sent_fn & fn_bits) & (1<<i)) {
host_add_code(keymap_fn_keycode(1<<i));
}
}
}
inline
static uint8_t new_layer(uint8_t fn_bits)
{
return (fn_bits ? keymap_fn_layer(fn_bits) : default_layer);
}

15
layer.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef LAYER_H
#define LAYER_H 1
#include <stdint.h>
extern uint8_t default_layer;
extern uint8_t current_layer;
/* return keycode for switch */
uint8_t layer_get_keycode(uint8_t row, uint8_t col);
/* process layer switching */
void layer_switching(uint8_t fn_bits);
#endif

16
led.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef LED_H
#define LED_H
#include "stdint.h"
/* keyboard LEDs */
#define USB_LED_NUM_LOCK 0
#define USB_LED_CAPS_LOCK 1
#define USB_LED_SCROLL_LOCK 2
#define USB_LED_COMPOSE 3
#define USB_LED_KANA 4
void led_set(uint8_t usb_led);
#endif

View File

@ -1,52 +1,5 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
VENDOR_ID = 0xFEED
PRODUCT_ID = 0xBEEF
MANUFACTURER = 't.m.k.'
PRODUCT = 't.m.k. Macway mod'
DESCRIPTION = 't.m.k. firmware for Macway mod'
# Target file name (without extension).
TARGET = tmk_macway
TARGET = macway
# Directory common source filess exist
COMMON_DIR = ..
@ -55,8 +8,12 @@ COMMON_DIR = ..
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = keymap.c \
matrix.c
TARGET_SRC = main_pjrc.c \
keymap.c \
matrix.c \
led.c
CONFIG_H = config.h
# MCU name, you MUST set this to match the board you are using
@ -74,4 +31,21 @@ MCU = atmega32u4 # Teensy 2.0
# 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
USB_EXTRA_ENABLE = yes # Audio control and System control
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
include $(COMMON_DIR)/Makefile.pjrc
include $(COMMON_DIR)/Makefile.common

46
macway/config.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef CONFIG_H
#define CONFIG_H
/* controller configuration */
#include "controller_teensy.h"
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xBEE0
#define MANUFACTURER t.m.k.
#define PRODUCT Macway mod
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod
/* matrix size */
#define MATRIX_ROWS 9
#define MATRIX_COLS 8
/* define if matrix has ghost */
#define MATRIX_HAS_GHOST
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
)
/* mouse keys */
#ifdef MOUSEKEY_ENABLE
# define MOUSEKEY_DELAY_TIME 192
#endif
/* PS/2 mouse */
#ifdef PS2_MOUSE_ENABLE
# define PS2_CLOCK_PORT PORTF
# define PS2_CLOCK_PIN PINF
# define PS2_CLOCK_DDR DDRF
# define PS2_CLOCK_BIT 0
# define PS2_DATA_PORT PORTF
# define PS2_DATA_PIN PINF
# define PS2_DATA_DDR DDRF
# define PS2_DATA_BIT 1
#endif
#endif

View File

@ -1,6 +0,0 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H 1
#include "controller_teensy.h"
#endif

BIN
macway/doc/back.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
macway/doc/case.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
macway/doc/keys.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
macway/doc/side.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
macway/doc/switch.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
macway/doc/teensy.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
macway/doc/wiring.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
macway/doc/withHHKB.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

BIN
macway/doc/withThinkPad.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -4,18 +4,15 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "usb_keyboard.h"
#include "usb_keycodes.h"
#include "matrix.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "keymap.h"
#define FN_KEYCODE(fn) (pgm_read_byte(&fn_keycode[(fn)]))
#define FN_LAYER(fn) (pgm_read_byte(&fn_layer[(fn)]))
#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.
#define KEYMAP( \
R1C1, R1C0, R2C0, R3C0, R4C0, R4C1, R5C1, R5C0, R6C0, R7C0, R8C0, R8C1, R6C1, R0C2, \
R1C2, R1C3, R2C3, R3C3, R4C3, R4C2, R5C2, R5C3, R6C3, R7C3, R8C3, R8C2, R6C2, \
@ -34,23 +31,32 @@
{ R8C0, R8C1, R8C2, R8C3, R8C4, R8C5, KB_NO, R8C7 } \
}
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
static int current_layer = 0;
static bool layer_used = false;
/* layer to change into while Fn key pressed */
static const int PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 2, 3 };
// 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
1, // Fn1
2, // Fn2
3, // Fn3
4, // Fn4
0, // Fn5
2, // Fn6
3 // Fn7
};
/* keycode to sent when Fn key released without using layer keys. */
// 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, // FN_0 [NOT USED]
KB_NO, // FN_1 layer 1
KB_QUOTE, // FN_2 layer 2
KB_SCOLON, // FN_3 layer 3
KB_SPACE, // FN_4 layer 4 [NOT USED]
KB_NO, // FN_5 [NOT USED]
KB_NO, // FN_6 layer 2
KB_NO // FN_7 layer 3
KB_NO, // Fn0
KB_NO, // Fn1
KB_SLSH, // Fn2
KB_SCLN, // Fn3
KB_SPC, // Fn4
KB_NO, // Fn5
KB_NO, // Fn6
KB_NO // Fn7
};
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
@ -60,37 +66,39 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
* |-----------------------------------------------------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| |
* |-----------------------------------------------------' |
* |Contro| A| S| D| F| G| H| J| K| L|Fn3|Fn2|Return |
* |Contro| A| S| D| F| G| H| J| K| L|Fn3| '|Return |
* |-----------------------------------------------------------|
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn1|
* |-----------------------------------------------------------|
* |Fn7|Gui |Alt |Space |Fn6 |\ |` | | |
* |Fn7|Gui |Alt |Fn4 |Alt |Gui|Fn6|Fn6|Ctr|
* `-----------------------------------------------------------'
*/
KEYMAP(KB_ESC, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9, KB_0, KB_MINS,KB_EQL, KB_BSPC, \
KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC, \
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, FN_2, KB_ENT, \
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_SLSH,KB_RSFT,FN_1, \
FN_7, KB_LGUI,KB_LALT,KB_SPC, FN_6, KB_BSLS,KB_GRV, KB_NO, KB_NO),
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, KB_FN3, KB_QUOT,KB_ENT, \
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_FN2, KB_RSFT,KB_FN1, \
KB_FN7, KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI,KB_FN6, KB_FN6, KB_RCTL),
/* Layer 1: HHKB mode (HHKB Fn)
* ,-----------------------------------------------------------.
* |Pow| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
* |-----------------------------------------------------------|
* |Caps | | | | | | | |Psc|Slk|Pus|Up | | |
* |-----------------------------------------------------' |
* |Contro| | | | | | *| /|Hom|PgU|Lef|Rig|Enter |
* |Contro|VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter |
* |-----------------------------------------------------------|
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
* |-----------------------------------------------------------|
* | |Gui |Alt | |Alt | | | | |
* | |Gui |Alt | |Alt |Gui| | |Ctr|
* `-----------------------------------------------------------'
*/
KEYMAP(KB_PWR, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_DEL, \
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_DEL, \
KB_CAPS,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PSCR,KB_SLCK,KB_BRK, KB_UP, KB_NO, \
KB_LCTL,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_ASTR,KP_SLSH,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_PLUS,KP_MINS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,FN_1, \
KB_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
KB_LCTL,KB_VOLD,KB_VOLU,KB_MUTE,KB_NO, KB_NO, KB_PAST,KB_PSLS,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PPLS,KB_PMNS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,KB_FN1, \
KB_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_NO, KB_NO, KB_NO, KB_RCTL),
/* Layer 2: Vi mode (Quote/Rmeta)
* ,-----------------------------------------------------------.
@ -98,38 +106,40 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
* |-----------------------------------------------------------|
* | \ |Hom|PgD|Up |PgU|End|Hom|PgD|PgU|End| | | | |
* |-----------------------------------------------------' |
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| |xxx| \ |
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| | | \ |
* |-----------------------------------------------------------|
* |Shift | | | | | |Hom|PgD|PgU|End| |Shift | |
* |Shift | | | | | |Hom|PgD|PgU|End|xxx|Shift | |
* |-----------------------------------------------------------|
* | |Gui |Alt |Space |xxxxx| | | | |
* | |Gui |Alt |Space |Alt |Gui|Fn6|Fn6|Ctr|
* `-----------------------------------------------------------'
*/
KEYMAP(KB_GRV, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_GRV, \
KB_BSLS,KB_HOME,KB_PGDN,KB_UP, KB_PGUP,KB_END, KB_HOME,KB_PGDN,KB_PGUP,KB_END, KB_NO, KB_NO, KB_NO, \
KB_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, FN_2, KB_BSLS, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
KB_NO, KB_LGUI,KB_LALT,KB_SPC, FN_6, KB_NO, KB_NO, KB_NO, KB_NO),
KB_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, KB_NO, KB_BSLS, \
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_FN2, KB_RSFT,KB_NO, \
KB_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI,KB_FN6, KB_FN6, KB_RCTL),
/* Layer 3: Mouse mode (Semicolon)
* ,-------------------------------------------------------- --.
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
* ,-----------------------------------------------------------.
* | `| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| ` |
* |-----------------------------------------------------------|
* |Tab |MwL|MwU|McU|MwD|MwR|MwL|MwD|MwU|MwR| | | | |
* | \ |MwL|MwD|McU|MwU|MwR|MwL|MwD|MwU|MwR| | | | |
* |-----------------------------------------------------' |
* |Contro|Mb1|Mb2|Mb3| | |McL|McD|McU|McR|xxx| |Return |
* |Contro| |McL|McD|McR| |McL|McD|McU|McR|xxx| | \ |
* |-----------------------------------------------------------|
* |Shift | | | | | |MwL|MwD|MwU|MwR| |Shift | |
* |Shift | | |Mb1|Mb2|Mb3|Mb2|Mb1| | | |Shift | |
* |-----------------------------------------------------------|
* |xxx|Gui |Alt |Mb1 |Alt | | | | |
* `-----------------------------------------------------------'
* Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel
*/
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_DEL, \
KB_TAB, MS_WH_L,MS_WH_U,MS_UP, MS_WH_D,MS_WH_R,MS_WH_L,MS_WH_D,MS_WH_U,MS_WH_R,KB_NO, KB_NO, KB_NO, \
KB_LCTL,KB_NO, MS_LEFT,MS_DOWN,MS_RGHT,KB_NO, MS_LEFT,MS_DOWN,MS_UP, MS_RGHT,FN_3, KB_NO, KB_ENT, \
KB_LSFT,KB_NO, MS_DOWN,KB_NO, KB_NO, KB_NO, MS_BTN2,MS_BTN1,MS_BTN2,MS_BTN3,KB_NO, KB_RSFT,KB_NO, \
FN_7, KB_LGUI,KB_LALT,MS_BTN1,KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
KEYMAP(KB_GRV, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_GRV, \
KB_BSLS,KB_WH_L,KB_WH_D,KB_MS_U,KB_WH_U,KB_WH_R,KB_WH_L,KB_WH_D,KB_WH_U,KB_WH_R,KB_NO, KB_NO, KB_NO, \
KB_LCTL,KB_NO, KB_MS_L,KB_MS_D,KB_MS_R,KB_NO, KB_MS_L,KB_MS_D,KB_MS_U,KB_MS_R,KB_FN3, KB_NO, KB_BSLS, \
KB_LSFT,KB_NO, KB_NO, KB_BTN1,KB_BTN2,KB_BTN3,KB_BTN2,KB_BTN1,KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
KB_FN7, KB_LGUI,KB_LALT,KB_BTN1,KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
/* Layer 4: Matias half keyboard style (Space)
* ,-----------------------------------------------------------.
@ -141,87 +151,28 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
* |-----------------------------------------------------------|
* |Shift | /| .| ,| M| N| B| V| C| X| Z|Shift | |
* |-----------------------------------------------------------|
* | |Gui |Alt |xxxxxxxxxxxxxxxxxxxxxx|Alt | | | | |
* | |Gui |Alt |xxxxxxxxxxxxxxxxxxxxxx|Alt |Gui| | |Ctr|
* `-----------------------------------------------------------'
*/
KEYMAP(KB_MINS,KB_0, KB_9, KB_8, KB_7, KB_6, KB_5, KB_4, KB_3, KB_2, KB_1, KB_NO, KB_NO, KB_ESC, \
KB_BSPC,KB_P, KB_O, KB_I, KB_U, KB_Y, KB_T, KB_R, KB_E, KB_W, KB_Q, KB_TAB, KB_TAB, \
KB_LCTL,KB_SCLN,KB_L, KB_K, KB_J, KB_H, KB_G, KB_F, KB_D, KB_S, KB_A, KB_RCTL,KB_RCTL, \
KB_LSFT,KB_SLSH,KB_DOT, KB_COMM,KB_M, KB_N, KB_B, KB_V, KB_C, KB_X, KB_Z, KB_RSFT,KB_NO, \
KB_NO, KB_LGUI,KB_LALT,FN_4, KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
KB_NO, KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI,KB_NO, KB_NO, KB_RCTL),
};
uint8_t keymap_get_keycode(int row, int col)
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
{
return keymap_get_keycodel(current_layer, row, col);
return KEYCODE(layer, row, col);
}
uint8_t keymap_get_keycodel(int layer, int row, int col)
uint8_t keymap_fn_layer(uint8_t fn_bits)
{
uint8_t code = KEYCODE(layer, row, col);
// normal key or mouse key
if (IS_KEY(code) || IS_MOUSE(code))
layer_used = true;
return code;
return pgm_read_byte(&fn_layer[biton(fn_bits)]);
}
inline
int keymap_get_layer(void)
uint8_t keymap_fn_keycode(uint8_t fn_bits)
{
return current_layer;
}
inline
int keymap_set_layer(int layer)
{
current_layer = layer;
return current_layer;
}
inline
bool keymap_is_special_mode(int fn_bits)
{
return (keyboard_modifier_keys == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI));
}
void keymap_fn_proc(int fn_bits)
{
// layer switching
static int last_bits = 0;
static uint8_t last_mod = 0;
if (usb_keyboard_has_key() || fn_bits == last_bits) {
// do nothing during press other than Fn key
return;
} else if (fn_bits == 0) {
// send key when Fn key is released without using the layer
if (!layer_used) {
uint8_t code = FN_KEYCODE(biton(last_bits));
if (code != KB_NO) {
if (IS_MOD(code)) {
keyboard_modifier_keys = last_mod | 1<<(code & 0x07);
} else {
keyboard_keys[0] = code;
keyboard_modifier_keys = last_mod;
}
usb_keyboard_send();
usb_keyboard_print();
usb_keyboard_clear();
}
}
last_bits = 0;
last_mod = 0;
layer_used = false;
keymap_set_layer(0); // default layer
} else if ((fn_bits & (fn_bits - 1)) == 0) {
// switch layer when just one Fn Key is pressed
last_bits = fn_bits;
last_mod = keyboard_modifier_keys;
layer_used = false;
keymap_set_layer(FN_LAYER(biton(fn_bits)));
debug("layer: "); phex(current_layer); debug("(");
debug_bin(last_bits); debug(")\n");
debug("last_mod: "); debug_hex(last_mod); debug("\n");
}
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
}

View File

@ -1,7 +0,0 @@
#ifndef KEYMAP_H
#define KEYMAP_H 1
#include "usb_keycodes.h"
#include "keymap_skel.h"
#endif

7
macway/led.c Normal file
View File

@ -0,0 +1,7 @@
#include "stdint.h"
#include "led.h"
void led_set(uint8_t usb_led)
{
}

View File

@ -5,56 +5,68 @@
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "matrix.h"
#include "print.h"
#include "util.h"
#include "matrix.h"
// matrix is active low. (key on: 0/key off: 1)
// row: Hi-Z(unselected)/low output(selected)
// PD0, PC7, PD7, PF6, PD6, PD1, PD2, PC6, PF7
// col: input w/pullup
// PB0-PB7
// matrix state buffer
uint8_t *matrix;
uint8_t *matrix_prev;
#if (MATRIX_COLS > 16)
# error "MATRIX_COLS must not exceed 16"
#endif
#if (MATRIX_ROWS > 255)
# error "MATRIX_ROWS must not exceed 255"
#endif
// matrix state buffer(1:on, 0:off)
#if (MATRIX_COLS <= 8)
static uint8_t *matrix;
static uint8_t *matrix_prev;
static uint8_t _matrix0[MATRIX_ROWS];
static uint8_t _matrix1[MATRIX_ROWS];
#else
static uint16_t *matrix;
static uint16_t *matrix_prev;
static uint16_t _matrix0[MATRIX_ROWS];
static uint16_t _matrix1[MATRIX_ROWS];
#endif
#ifdef MATRIX_HAS_GHOST
static bool matrix_has_ghost_in_row(uint8_t row);
#endif
static uint8_t read_col(void);
static void unselect_rows(void);
static void select_row(uint8_t row);
inline
int matrix_rows(void)
uint8_t matrix_rows(void)
{
return MATRIX_ROWS;
}
inline
int matrix_cols(void)
uint8_t matrix_cols(void)
{
return MATRIX_COLS;
}
// this must be called once before matrix_scan.
void matrix_init(void)
{
// initialize row and col
unselect_rows();
// Input with pull-up(DDR:0, PORT:1)
DDRB = 0x00;
PORTB = 0xFF;
// initialize matrix state: all keys off
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
matrix = _matrix0;
matrix_prev = _matrix1;
}
int matrix_scan(void)
uint8_t matrix_scan(void)
{
uint8_t *tmp;
@ -62,41 +74,49 @@ int matrix_scan(void)
matrix_prev = matrix;
matrix = tmp;
for (int i = 0; i < MATRIX_ROWS; i++) {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
unselect_rows();
select_row(i);
_delay_us(30); // without this wait read unstable value.
matrix[i] = ~read_col();
unselect_rows();
}
unselect_rows();
return 1;
}
bool matrix_is_modified(void)
{
for (int i = 0; i < MATRIX_ROWS; i++) {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
if (matrix[i] != matrix_prev[i])
return true;
}
return false;
}
inline
bool matrix_has_ghost(void)
{
for (int i = 0; i < MATRIX_ROWS; i++) {
#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(int row, int col)
bool matrix_is_on(uint8_t row, uint8_t col)
{
return (matrix[row] & (1<<col));
}
inline
uint16_t matrix_get_row(int row)
#if (MATRIX_COLS <= 8)
uint8_t matrix_get_row(uint8_t row)
#else
uint16_t matrix_get_row(uint8_t row)
#endif
{
return matrix[row];
}
@ -104,25 +124,37 @@ uint16_t matrix_get_row(int row)
void matrix_print(void)
{
print("\nr/c 01234567\n");
for (int row = 0; row < matrix_rows(); row++) {
for (uint8_t row = 0; row < matrix_rows(); row++) {
phex(row); print(": ");
#if (MATRIX_COLS <= 8)
pbin_reverse(matrix_get_row(row));
#else
pbin_reverse16(matrix_get_row(row));
#endif
#ifdef MATRIX_HAS_GHOST
if (matrix_has_ghost_in_row(row)) {
print(" <ghost");
}
#endif
print("\n");
}
}
int matrix_key_count(void)
uint8_t matrix_key_count(void)
{
int count = 0;
for (int i = 0; i < MATRIX_ROWS; i++) {
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
#if (MATRIX_COLS <= 8)
count += bitpop(matrix[i]);
#else
count += bitpop16(matrix[i]);
#endif
}
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
@ -130,102 +162,74 @@ static bool matrix_has_ghost_in_row(uint8_t row)
return false;
// ghost exists in case same state as other row
for (int i=0; i < MATRIX_ROWS; i++) {
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 uint8_t read_col(void)
{
return PINB;
}
inline
static void unselect_rows(void)
{
DDRD = 0x00;
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
// Hi-Z(DDR:0, PORT:0) to unselect
DDRC &= ~0b11000000; // PC: 7,6
PORTC &= ~0b11000000;
DDRD &= ~0b11000111; // PD: 7,6,2,1,0
PORTD &= ~0b11000111;
DDRF &= ~0b11000000; // PF: 7,6
PORTF &= ~0b11000000;
}
inline
static void select_row(uint8_t row)
{
// Output low(DDR:1, PORT:0) to select
// row: 0 1 2 3 4 5 6 7 8
// pin: PD0, PC7, PD7, PF6, PD6, PD1, PD2, PC6, PF7
switch (row) {
case 0:
DDRD = (1<<0);
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRD |= (1<<0);
PORTD &= ~(1<<0);
break;
case 1:
DDRD = 0x00;
PORTD = 0x00;
DDRC = (1<<7);
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRC |= (1<<7);
PORTC &= ~(1<<7);
break;
case 2:
DDRD = (1<<7);
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRD |= (1<<7);
PORTD &= ~(1<<7);
break;
case 3:
DDRD = 0x00;
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = (1<<6);
PORTF = 0x00;
DDRF |= (1<<6);
PORTF &= ~(1<<6);
break;
case 4:
DDRD = (1<<6);
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRD |= (1<<6);
PORTD &= ~(1<<6);
break;
case 5:
DDRD = (1<<1);
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRD |= (1<<1);
PORTD &= ~(1<<1);
break;
case 6:
DDRD = (1<<2);
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRD |= (1<<2);
PORTD &= ~(1<<2);
break;
case 7:
DDRD = 0x00;
PORTD = 0x00;
DDRC = (1<<6);
PORTC = 0x00;
DDRF = 0x00;
PORTF = 0x00;
DDRC |= (1<<6);
PORTC &= ~(1<<6);
break;
case 8:
DDRD = 0x00;
PORTD = 0x00;
DDRC = 0x00;
PORTC = 0x00;
DDRF = (1<<7);
PORTF = 0x00;
DDRF |= (1<<7);
PORTF &= ~(1<<7);
break;
}
}

View File

@ -1,15 +0,0 @@
#ifndef MATRIX_H
#define MATRIX_H 1
#include <stdint.h>
#include "matrix_skel.h"
#define MATRIX_ROWS 9
#define MATRIX_COLS 8
extern uint8_t *matrix;
extern uint8_t *matrix_prev;
#endif

View File

@ -28,27 +28,32 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "keyboard.h"
#include "usb.h"
#include "matrix_skel.h"
#include "key_process.h"
#include "matrix.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "controller.h"
#include "jump_bootloader.h"
#ifdef PS2_MOUSE_ENABLE
# include "ps2_mouse.h"
#endif
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
bool debug_enable = false;
bool debug_matrix = false;
bool debug_keyboard = false;
bool debug_mouse = false;
uint16_t idle_count=0;
int main(void)
{
DEBUG_LED_CONFIG;
DEBUG_LED_OFF;
// set for 16 MHz clock
CPU_PRESCALE(0);
@ -58,25 +63,9 @@ int main(void)
usb_init();
while (!usb_configured()) /* wait */ ;
// Configure timer 0 to generate a timer overflow interrupt every
// 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock
// This demonstrates how to use interrupts to implement a simple
// inactivity timeout.
TCCR0A = 0x00;
TCCR0B = 0x05;
TIMSK0 = (1<<TOIE0);
matrix_init();
keyboard_init();
matrix_scan();
// debug on by pressing down any 4 or more keys during boot time.
if (matrix_key_count() >= 4) {
print_enable = true;
debug_enable = true;
}
/* wait for debug pipe ready */
if (print_enable) {
if (matrix_key_count() >= 3) {
#ifdef DEBUG_LED
for (int i = 0; i < 6; i++) {
DEBUG_LED_CONFIG;
@ -86,24 +75,23 @@ int main(void)
_delay_ms(500);
}
#else
_delay_ms(6000);
_delay_ms(5000);
#endif
print_enable = true;
debug_enable = true;
debug_matrix = true;
debug_keyboard = true;
debug_mouse = true;
print("debug enabled.\n");
}
// print description
print(STR(DESCRIPTION) "\n");
if (matrix_key_count() >= 4) {
print("jump to bootloader...\n");
_delay_ms(1000);
jump_bootloader(); // not return
}
while (1) {
proc_matrix();
_delay_ms(2);
keyboard_proc();
}
}
// This interrupt routine is run approx 61 times per second.
// A very simple inactivity timeout is implemented, where we
// will send a space character and print a message to the
// hid_listen debug message window.
ISR(TIMER0_OVF_vect)
{
idle_count++;
}

62
main_vusb.c Normal file
View File

@ -0,0 +1,62 @@
/* PS/2 to USB keyboard converter
* 2011/02/20
* Copyright (c) 2011 tmk
*/
/* Name: main.c
* Project: hid-mouse, a very simple HID example
* Author: Christian Starkjohann
* Creation Date: 2008-04-07
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: main.c 790 2010-05-30 21:00:26Z cs $
*/
#include <stdint.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usbdrv.h"
#include "oddebug.h"
#include "host_vusb.h"
#include "keyboard.h"
#if 0
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
#define DEBUGP(x) do { PORTC = x; } while (0)
#else
#define DEBUGP_INIT()
#define DEBUGP(x)
#endif
int main(void)
{
DEBUGP_INIT();
wdt_enable(WDTO_1S);
odDebugInit();
usbInit();
/* enforce re-enumeration, do this while interrupts are disabled! */
usbDeviceDisconnect();
uint8_t i = 0;
/* fake USB disconnect for > 250 ms */
while(--i){
wdt_reset();
_delay_ms(1);
}
usbDeviceConnect();
keyboard_init();
sei();
while (1) {
DEBUGP(0x1);
wdt_reset();
usbPoll();
DEBUGP(0x2);
keyboard_proc();
DEBUGP(0x3);
host_vusb_keyboard_send();
}
}

View File

@ -1,26 +1,30 @@
#ifndef MATRIX_SKEL_H
#define MATRIX_SKEL_H 1
#ifndef MATRIX_H
#define MATRIX_H
#include <stdbool.h>
/* number of matrix rows */
int matrix_rows(void);
uint8_t matrix_rows(void);
/* number of matrix columns */
int matrix_cols(void);
uint8_t matrix_cols(void);
/* intialize matrix for scaning. should be called once. */
void matrix_init(void);
/* scan all key states on matrix */
int matrix_scan(void);
uint8_t matrix_scan(void);
/* whether modified from previous scan. used after matrix_scan. */
bool matrix_is_modified(void);
/* whether ghosting occur on matrix. */
bool matrix_has_ghost(void);
/* whether a swtich is on */
bool matrix_is_on(int row, int col);
bool matrix_is_on(uint8_t row, uint8_t col);
/* matrix state on row */
uint16_t matrix_get_row(int row);
#if (MATRIX_COLS <= 8)
uint8_t matrix_get_row(uint8_t row);
#else
uint16_t matrix_get_row(uint8_t row);
#endif
/* count keys pressed */
int matrix_key_count(void);
uint8_t matrix_key_count(void);
/* print matrix for debug */
void matrix_print(void);

115
mousekey.c Normal file
View File

@ -0,0 +1,115 @@
#include <stdint.h>
#include <util/delay.h>
#include "usb_keycodes.h"
#include "host.h"
#include "timer.h"
#include "print.h"
#include "debug.h"
#include "mousekey.h"
static report_mouse_t report;
static report_mouse_t report_prev;
static uint8_t mousekey_repeat = 0;
static void mousekey_debug(void);
/*
* TODO: fix acceleration algorithm
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys
*/
#ifndef MOUSEKEY_DELAY_TIME
# define MOUSEKEY_DELAY_TIME 255
#endif
// acceleration parameters
uint8_t mousekey_move_unit = 2;
uint8_t mousekey_resolution = 5;
static inline uint8_t move_unit(void)
{
uint16_t unit = 5 + mousekey_repeat*2;
return (unit > 63 ? 63 : unit);
}
void mousekey_decode(uint8_t code)
{
if (code == KB_MS_UP) report.y = -move_unit();
else if (code == KB_MS_DOWN) report.y = move_unit();
else if (code == KB_MS_LEFT) report.x = -move_unit();
else if (code == KB_MS_RIGHT) report.x = move_unit();
else if (code == KB_MS_BTN1) report.buttons |= MOUSE_BTN1;
else if (code == KB_MS_BTN2) report.buttons |= MOUSE_BTN2;
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3;
else if (code == KB_MS_BTN4) report.buttons |= MOUSE_BTN4;
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5;
else if (code == KB_MS_WH_UP) report.v += 1;
else if (code == KB_MS_WH_DOWN) report.v -= 1;
else if (code == KB_MS_WH_LEFT) report.h -= 1;
else if (code == KB_MS_WH_RIGHT)report.h += 1;
}
bool mousekey_changed(void)
{
return (report.buttons != report_prev.buttons ||
report.x || report.y || report.v || report.h);
}
void mousekey_send(void)
{
static uint16_t last_timer = 0;
if (!mousekey_changed()) {
mousekey_repeat = 0;
mousekey_clear_report();
return;
}
// send immediately when buttun state is changed
if (report.buttons == report_prev.buttons) {
if (timer_elapsed(last_timer) < 5) {
mousekey_clear_report();
return;
}
}
if (mousekey_repeat != 0xFF) {
mousekey_repeat++;
}
if (report.x && report.y) {
report.x *= 0.7;
report.y *= 0.7;
}
mousekey_debug();
host_mouse_send(&report);
report_prev = report;
last_timer = timer_read();
mousekey_clear_report();
}
void mousekey_clear_report(void)
{
report.buttons = 0;
report.x = 0;
report.y = 0;
report.v = 0;
report.h = 0;
}
static void mousekey_debug(void)
{
if (!debug_mouse) return;
print("mousekey[btn|x y v h]: ");
phex(report.buttons); print("|");
phex(report.x); print(" ");
phex(report.y); print(" ");
phex(report.v); print(" ");
phex(report.h);
phex(mousekey_repeat);
print("\n");
}

75
mousekey.c.bak Normal file
View File

@ -0,0 +1,75 @@
#include <stdint.h>
#include <util/delay.h>
#include "usb_keycodes.h"
#include "usb_mouse.h"
#include "mousekey.h"
static int8_t mousekey_x = 0;
static int8_t mousekey_y = 0;
static int8_t mousekey_v = 0;
static int8_t mousekey_h = 0;
static uint8_t mousekey_btn = 0;
static uint8_t mousekey_btn_prev = 0;
static uint8_t mousekey_repeat = 0;
/*
* TODO: fix acceleration algorithm
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys
*/
#ifndef MOUSEKEY_DELAY_TIME
# define MOUSEKEY_DELAY_TIME 255
#endif
static inline uint8_t move_unit(void)
{
return 10 + (mousekey_repeat < 50 ? mousekey_repeat/5 : 10);
}
void mousekey_decode(uint8_t code)
{
if (code == KB_MS_UP) mousekey_y -= move_unit();
else if (code == KB_MS_DOWN) mousekey_y += move_unit();
else if (code == KB_MS_LEFT) mousekey_x -= move_unit();
else if (code == KB_MS_RIGHT) mousekey_x += move_unit();
else if (code == KB_MS_BTN1) mousekey_btn |= MOUSE_BTN1;
else if (code == KB_MS_BTN2) mousekey_btn |= MOUSE_BTN2;
else if (code == KB_MS_BTN3) mousekey_btn |= MOUSE_BTN3;
else if (code == KB_MS_BTN4) mousekey_btn |= MOUSE_BTN4;
else if (code == KB_MS_BTN5) mousekey_btn |= MOUSE_BTN5;
else if (code == KB_MS_WH_UP) mousekey_v += 1;
else if (code == KB_MS_WH_DOWN) mousekey_v -= 1;
else if (code == KB_MS_WH_LEFT) mousekey_h -= 1;
else if (code == KB_MS_WH_RIGHT) mousekey_h += 1;
}
bool mousekey_changed(void)
{
return (mousekey_x || mousekey_y || mousekey_v || mousekey_h || mousekey_btn != mousekey_btn_prev);
}
void mousekey_usb_send(void)
{
if (mousekey_changed()) {
mousekey_btn_prev = mousekey_btn;
if (mousekey_x && mousekey_y)
usb_mouse_send(mousekey_x*0.7, mousekey_y*0.7, mousekey_v, mousekey_h, mousekey_btn);
else
usb_mouse_send(mousekey_x, mousekey_y, mousekey_v, mousekey_h, mousekey_btn);
usb_mouse_print(mousekey_x, mousekey_y, mousekey_v, mousekey_h, mousekey_btn);
if (mousekey_x || mousekey_y || mousekey_v || mousekey_h)
_delay_ms(MOUSEKEY_DELAY_TIME >> (mousekey_repeat < 5 ? mousekey_repeat : 4));
mousekey_repeat++;
} else {
mousekey_repeat = 0;
}
mousekey_x = 0;
mousekey_y = 0;
mousekey_v = 0;
mousekey_h = 0;
mousekey_btn = 0;
}

12
mousekey.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef MOUSEKEY_H
#define MOUSEKEY_H
#include <stdbool.h>
#include "host.h"
void mousekey_decode(uint8_t code);
bool mousekey_changed(void);
void mousekey_send(void);
void mousekey_clear_report(void);
#endif

11
mousekey.h.bak Normal file
View File

@ -0,0 +1,11 @@
#ifndef MOUSEKEY_H
#define MOUSEKEY_H
#include <stdbool.h>
void mousekey_decode(uint8_t code);
bool mousekey_changed(void);
void mousekey_usb_send(void);
#endif

166
pjrc/host.c Normal file
View File

@ -0,0 +1,166 @@
#include <stdint.h>
#include <avr/interrupt.h>
#include "usb_keycodes.h"
#include "usb_keyboard.h"
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
#include "usb_mouse.h"
#endif
#ifdef USB_EXTRA_ENABLE
#include "usb_extra.h"
#endif
#include "debug.h"
#include "host.h"
#include "util.h"
#ifdef USB_NKRO_ENABLE
bool keyboard_nkro = false;
#endif
static report_keyboard_t report0;
static report_keyboard_t report1;
report_keyboard_t *keyboard_report = &report0;
report_keyboard_t *keyboard_report_prev = &report1;
static inline void add_key_byte(uint8_t code);
static inline void add_key_bit(uint8_t code);
uint8_t host_keyboard_leds(void)
{
return usb_keyboard_leds;
}
/* keyboard report operations */
void host_add_key(uint8_t key)
{
#ifdef USB_NKRO_ENABLE
if (keyboard_nkro) {
add_key_bit(key);
return;
}
#endif
add_key_byte(key);
}
void host_add_mod_bit(uint8_t mod)
{
keyboard_report->mods |= mod;
}
void host_set_mods(uint8_t mods)
{
keyboard_report->mods = mods;
}
void host_add_code(uint8_t code)
{
if (IS_MOD(code)) {
host_add_mod_bit(MOD_BIT(code));
} else {
host_add_key(code);
}
}
void host_swap_keyboard_report(void)
{
uint8_t sreg = SREG;
cli();
report_keyboard_t *tmp = keyboard_report_prev;
keyboard_report_prev = keyboard_report;
keyboard_report = tmp;
SREG = sreg;
}
void host_clear_keyboard_report(void)
{
keyboard_report->mods = 0;
for (int8_t i = 0; i < REPORT_KEYS; i++) {
keyboard_report->keys[i] = 0;
}
}
uint8_t host_has_anykey(void)
{
uint8_t cnt = 0;
for (int i = 0; i < REPORT_KEYS; i++) {
if (keyboard_report->keys[i])
cnt++;
}
return cnt;
}
uint8_t host_get_first_key(void)
{
#ifdef USB_NKRO_ENABLE
if (keyboard_nkro) {
uint8_t i = 0;
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++)
;
return i<<3 | biton(keyboard_report->keys[i]);
}
#endif
return keyboard_report->keys[0];
}
void host_send_keyboard_report(void)
{
usb_keyboard_send_report(keyboard_report);
}
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
void host_mouse_send(report_mouse_t *report)
{
usb_mouse_send(report->x, report->y, report->v, report->h, report->buttons);
}
#endif
#ifdef USB_EXTRA_ENABLE
void host_system_send(uint16_t data)
{
usb_extra_system_send(data);
}
void host_consumer_send(uint16_t data)
{
static uint16_t last_data = 0;
if (data == last_data) return;
last_data = data;
usb_extra_consumer_send(data);
}
#endif
static inline void add_key_byte(uint8_t code)
{
// TODO: fix ugly code
int8_t i = 0;
int8_t empty = -1;
for (; i < REPORT_KEYS; i++) {
if (keyboard_report_prev->keys[i] == code) {
keyboard_report->keys[i] = code;
break;
}
if (empty == -1 &&
keyboard_report_prev->keys[i] == 0 &&
keyboard_report->keys[i] == 0) {
empty = i;
}
}
if (i == REPORT_KEYS) {
if (empty != -1) {
keyboard_report->keys[empty] = code;
}
}
}
static inline void add_key_bit(uint8_t code)
{
if ((code>>3) < REPORT_KEYS) {
keyboard_report->keys[code>>3] |= 1<<(code&7);
} else {
debug("add_key_bit: can't add: "); phex(code); debug("\n");
}
}

40
pjrc/jump_bootloader.c Normal file
View File

@ -0,0 +1,40 @@
// this code from:
// http://www.pjrc.com/teensy/jump_to_bootloader.html
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void jump_bootloader(void) {
cli();
// disable watchdog, if enabled
// disable all peripherals
UDCON = 1;
USBCON = (1<<FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5);
#if defined(__AVR_AT90USB162__) // Teensy 1.0
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
DDRB = 0; DDRC = 0; DDRD = 0;
PORTB = 0; PORTC = 0; PORTD = 0;
asm volatile("jmp 0x3E00");
#elif defined(__AVR_ATmega32U4__) // Teensy 2.0
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
asm volatile("jmp 0x7E00");
#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
asm volatile("jmp 0xFC00");
#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
asm volatile("jmp 0x1FC00");
#endif
}

View File

@ -21,6 +21,8 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
@ -28,6 +30,7 @@
#include "usb_keyboard.h"
#include "usb_mouse.h"
#include "usb_debug.h"
#include "usb_extra.h"
#include "print.h"
#include "util.h"
@ -81,15 +84,30 @@
#define ENDPOINT0_SIZE 32
bool remote_wakeup = false;
bool suspend = false;
// 0:control endpoint is enabled automatically by controller.
static const uint8_t PROGMEM endpoint_config_table[] = {
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation)
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1
#ifdef USB_MOUSE_ENABLE
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2
#else
0, // 2
#endif
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3
0, // 4
0, // 5
0, // 6
#ifdef USB_EXTRA_ENABLE
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4
#else
0, // 4
#endif
#ifdef USB_NKRO_ENABLE
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5
#else
0, // 5
#endif
0, // 6
};
@ -106,7 +124,7 @@ static const uint8_t PROGMEM endpoint_config_table[] = {
// spec and relevant portions of any USB class specifications!
static uint8_t PROGMEM device_descriptor[] = {
const static uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
@ -124,7 +142,7 @@ static uint8_t PROGMEM device_descriptor[] = {
};
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
static uint8_t PROGMEM keyboard_hid_report_desc[] = {
const static uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
@ -148,95 +166,110 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, 0x06, // Report Count (6),
0x95, KBD_REPORT_KEYS, // Report Count (),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x68, // Logical Maximum(104),
0x25, 0xFF, // Logical Maximum(255),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x68, // Usage Maximum (104),
0x29, 0xFF, // Usage Maximum (255),
0x81, 0x00, // Input (Data, Array),
0xc0 // End Collection
};
#ifdef USB_NKRO_ENABLE
const static uint8_t PROGMEM keyboard2_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
// bitmap of modifiers
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
// LED output report
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute),
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant),
// bitmap of keys
0x95, KBD2_REPORT_KEYS*8, // Report Count (),
0x75, 0x01, // Report Size (1),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum(1),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, KBD2_REPORT_KEYS*8-1, // Usage Maximum (),
0x81, 0x02, // Input (Data, Variable, Absolute),
0xc0 // End Collection
};
#endif
#ifdef USB_MOUSE_ENABLE
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
// http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
// http://www.keil.com/forum/15671/
// http://www.microsoft.com/whdc/device/input/wheel.mspx
static uint8_t PROGMEM mouse_hid_report_desc[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
// ------------------------------ Buttons
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x05, // REPORT_COUNT (5)
0x81, 0x02, // INPUT (Data,Var,Abs)
// ------------------------------ Padding
0x75, 0x03, // REPORT_SIZE (3)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
// ------------------------------ X,Y position
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Vertical wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x01, // PHYSICAL_MINIMUM (1)
0x45, 0x04, // PHYSICAL_MAXIMUM (4)
0x75, 0x02, // REPORT_SIZE (2)
0x95, 0x01, // REPORT_COUNT (1)
0xa4, // PUSH
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Vertical wheel
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Horizontal wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0xb4, // POP
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Padding for Feature report
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x04, // REPORT_SIZE (4)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
// ------------------------------ Horizontal wheel
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x0a, 0x38, 0x02, // USAGE (AC Pan)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
const static uint8_t PROGMEM mouse_hid_report_desc[] = {
/* mouse */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
//0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
// ---------------------------- Buttons
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x05, // REPORT_COUNT (5)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x03, // REPORT_SIZE (3)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
// ---------------------------- X,Y position
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
// ---------------------------- Vertical wheel
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x06, // INPUT (Data,Var,Rel)
// ---------------------------- Horizontal wheel
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x0a, 0x38, 0x02, // USAGE (AC Pan)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
};
#endif
static uint8_t PROGMEM debug_hid_report_desc[] = {
const static uint8_t PROGMEM debug_hid_report_desc[] = {
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
0x09, 0x74, // Usage 0x74
0xA1, 0x53, // Collection 0x53
@ -249,26 +282,84 @@ static uint8_t PROGMEM debug_hid_report_desc[] = {
0xC0 // end collection
};
#define CONFIG1_DESC_SIZE (9+(9+9+7)+(9+9+7)+(9+9+7))
#define KEYBOARD_HID_DESC_OFFSET (9+9)
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)+9)
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)+(9+9+7)+9)
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
#ifdef USB_EXTRA_ENABLE
// audio controls & system controls
// http://www.microsoft.com/whdc/archive/w2kbd.mspx
const static uint8_t PROGMEM extra_hid_report_desc[] = {
/* system control */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x80, // USAGE (System Control)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORT_ID_SYSTEM, // REPORT_ID (2)
0x15, 0x01, // LOGICAL_MINIMUM (0x1)
0x25, 0xb7, // LOGICAL_MAXIMUM (0xb7)
0x19, 0x01, // USAGE_MINIMUM (0x1)
0x29, 0xb7, // USAGE_MAXIMUM (0xb7)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x00, // INPUT (Data,Array,Abs)
0xc0, // END_COLLECTION
/* consumer */
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x09, 0x01, // USAGE (Consumer Control)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORT_ID_CONSUMER, // REPORT_ID (3)
0x15, 0x01, // LOGICAL_MINIMUM (0x1)
0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c)
0x19, 0x01, // USAGE_MINIMUM (0x1)
0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x00, // INPUT (Data,Array,Abs)
0xc0, // END_COLLECTION
};
#endif
#define KBD_HID_DESC_NUM 0
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9)
#ifdef USB_MOUSE_ENABLE
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
# define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9)
#else
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
#endif
#define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9)
#ifdef USB_EXTRA_ENABLE
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 1)
# define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
#else
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0)
#endif
#ifdef USB_NKRO_ENABLE
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
#else
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
#endif
#define NUM_INTERFACES (KBD2_HID_DESC_NUM + 1)
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES)
const static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
3, // bNumInterfaces
NUM_INTERFACES, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
0xA0, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
KBD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
@ -287,11 +378,12 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
KBD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
1, // bInterval
KBD_SIZE, 0, // wMaxPacketSize
10, // bInterval
#ifdef USB_MOUSE_ENABLE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
@ -299,8 +391,13 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
// ThinkPad T23 BIOS doesn't work with boot mouse.
0x00, // bInterfaceSubClass (0x01 = Boot)
0x00, // bInterfaceProtocol (0x02 = Mouse)
/*
0x01, // bInterfaceSubClass (0x01 = Boot)
0x02, // bInterfaceProtocol (0x02 = Mouse)
*/
0, // iInterface
// HID descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
@ -318,6 +415,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
0x03, // bmAttributes (0x03=intr)
MOUSE_SIZE, 0, // wMaxPacketSize
1, // bInterval
#endif
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
@ -344,7 +442,65 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_TX_SIZE, 0, // wMaxPacketSize
1 // bInterval
1, // bInterval
#ifdef USB_EXTRA_ENABLE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
EXTRA_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(extra_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
EXTRA_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
EXTRA_SIZE, 0, // wMaxPacketSize
10, // bInterval
#endif
#ifdef USB_NKRO_ENABLE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KBD2_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass (0x01 = Boot)
0x00, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard2_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KBD2_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KBD2_SIZE, 0, // wMaxPacketSize
1, // bInterval
#endif
};
// If you're desperate for a little extra code memory, these strings
@ -355,17 +511,17 @@ struct usb_string_descriptor_struct {
uint8_t bDescriptorType;
int16_t wString[];
};
static struct usb_string_descriptor_struct PROGMEM string0 = {
const static struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static struct usb_string_descriptor_struct PROGMEM string1 = {
const static struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
static struct usb_string_descriptor_struct PROGMEM string2 = {
const static struct usb_string_descriptor_struct PROGMEM string2 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
@ -378,21 +534,29 @@ static struct descriptor_list_struct {
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
} const PROGMEM descriptor_list[] = {
// DEVICE descriptor
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
// CONFIGURATION descriptor
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
// HID REPORT
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
// HID REPORT
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
// HID/REPORT descriptors
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9},
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
#ifdef USB_MOUSE_ENABLE
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
// HID REPORT
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
#endif
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
// STRING descriptor
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
#ifdef USB_EXTRA_ENABLE
{0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9},
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)},
#endif
#ifdef USB_NKRO_ENABLE
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9},
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)},
#endif
// STRING descriptors
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
@ -427,7 +591,7 @@ void usb_init(void)
USB_CONFIG(); // start USB clock
UDCON = 0; // enable attach resistor
usb_configuration = 0;
UDIEN = (1<<EORSTE)|(1<<SOFE);
UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE);
sei();
}
@ -435,7 +599,12 @@ void usb_init(void)
// number selected by the HOST
uint8_t usb_configured(void)
{
return usb_configuration;
return usb_configuration && !suspend;
}
void usb_remote_wakeup(void)
{
UDCON |= (1<<RMWKUP);
}
@ -458,6 +627,11 @@ ISR(USB_GEN_vect)
intbits = UDINT;
UDINT = 0;
if (intbits & (1<<SUSPI)) {
suspend = true;
} else {
suspend = false;
}
if (intbits & (1<<EORSTI)) {
UENUM = 0;
UECONX = 1;
@ -478,16 +652,22 @@ ISR(USB_GEN_vect)
UEINTX = 0x3A;
}
}
if (keyboard_idle_config && (++div4 & 3) == 0) {
UENUM = KEYBOARD_ENDPOINT;
/* TODO: should keep IDLE rate on each keyboard interface */
#ifdef USB_NKRO_ENABLE
if (!keyboard_nkro && usb_keyboard_idle_config && (++div4 & 3) == 0) {
#else
if (usb_keyboard_idle_config && (++div4 & 3) == 0) {
#endif
UENUM = KBD_ENDPOINT;
if (UEINTX & (1<<RWAL)) {
keyboard_idle_count++;
if (keyboard_idle_count == keyboard_idle_config) {
keyboard_idle_count = 0;
UEDATX = keyboard_modifier_keys;
usb_keyboard_idle_count++;
if (usb_keyboard_idle_count == usb_keyboard_idle_config) {
usb_keyboard_idle_count = 0;
UEDATX = keyboard_report_prev->mods;
UEDATX = 0;
for (i=0; i<6; i++) {
UEDATX = keyboard_keys[i];
uint8_t keys = usb_keyboard_protocol ? KBD_REPORT_KEYS : 6;
for (i=0; i<keys; i++) {
UEDATX = keyboard_report_prev->keys[i];
}
UEINTX = 0x3A;
}
@ -604,10 +784,12 @@ ISR(USB_COM_vect)
for (i=1; i<=6; i++) {
UENUM = i;
en = pgm_read_byte(cfg++);
UECONX = en;
if (en) {
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
if (en) {
UECONX = (1<<EPEN);
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
} else {
UECONX = 0;
}
}
UERST = 0x7E;
@ -636,9 +818,9 @@ ISR(USB_COM_vect)
usb_send_in();
return;
}
#ifdef SUPPORT_ENDPOINT_HALT
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
&& bmRequestType == 0x02 && wValue == 0) {
if (bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) {
#ifdef SUPPORT_ENDPOINT_HALT
if (bmRequestType == 0x02 && wValue == ENDPOINT_HALT) {
i = wIndex & 0x7F;
if (i >= 1 && i <= MAX_ENDPOINT) {
usb_send_in();
@ -652,29 +834,39 @@ ISR(USB_COM_vect)
}
return;
}
}
#endif
if (bmRequestType == 0x00 && wValue == DEVICE_REMOTE_WAKEUP) {
if (bRequest == SET_FEATURE) {
remote_wakeup = true;
} else {
remote_wakeup = false;
}
usb_send_in();
return;
}
}
#endif
if (wIndex == KEYBOARD_INTERFACE) {
if (wIndex == KBD_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
UEDATX = keyboard_modifier_keys;
UEDATX = keyboard_report->mods;
UEDATX = 0;
for (i=0; i<6; i++) {
UEDATX = keyboard_keys[i];
UEDATX = keyboard_report->keys[i];
}
usb_send_in();
return;
}
if (bRequest == HID_GET_IDLE) {
usb_wait_in_ready();
UEDATX = keyboard_idle_config;
UEDATX = usb_keyboard_idle_config;
usb_send_in();
return;
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = keyboard_protocol;
UEDATX = usb_keyboard_protocol;
usb_send_in();
return;
}
@ -682,32 +874,33 @@ ISR(USB_COM_vect)
if (bmRequestType == 0x21) {
if (bRequest == HID_SET_REPORT) {
usb_wait_receive_out();
keyboard_leds = UEDATX;
usb_keyboard_leds = UEDATX;
usb_ack_out();
usb_send_in();
return;
}
if (bRequest == HID_SET_IDLE) {
keyboard_idle_config = (wValue >> 8);
keyboard_idle_count = 0;
usb_keyboard_idle_config = (wValue >> 8);
usb_keyboard_idle_count = 0;
//usb_wait_in_ready();
usb_send_in();
return;
}
if (bRequest == HID_SET_PROTOCOL) {
keyboard_protocol = wValue;
usb_keyboard_protocol = wValue;
//usb_wait_in_ready();
usb_send_in();
return;
}
}
}
#ifdef USB_MOUSE_ENABLE
if (wIndex == MOUSE_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
if (wValue == HID_REPORT_INPUT) {
usb_wait_in_ready();
UEDATX = mouse_buttons;
UEDATX = 0;
UEDATX = 0;
UEDATX = 0;
UEDATX = 0;
@ -723,19 +916,20 @@ ISR(USB_COM_vect)
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = mouse_protocol;
UEDATX = usb_mouse_protocol;
usb_send_in();
return;
}
}
if (bmRequestType == 0x21) {
if (bRequest == HID_SET_PROTOCOL) {
mouse_protocol = wValue;
usb_mouse_protocol = wValue;
usb_send_in();
return;
}
}
}
#endif
if (wIndex == DEBUG_INTERFACE) {
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
len = wLength;

View File

@ -2,13 +2,16 @@
#define USB_H 1
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
extern bool remote_wakeup;
extern bool suspend;
void usb_init(void); // initialize everything
uint8_t usb_configured(void); // is the USB port configured
void usb_remote_wakeup(void);
#define EP_TYPE_CONTROL 0x00
@ -78,5 +81,28 @@ uint8_t usb_configured(void); // is the USB port configured
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
// HID feature selectors
#define DEVICE_REMOTE_WAKEUP 1
#define ENDPOINT_HALT 0
#define TEST_MODE 2
/*------------------------------------------------------------------*
* Keyboard descriptor setting
*------------------------------------------------------------------*/
#define KBD_INTERFACE 0
#define KBD_ENDPOINT 1
#define KBD_SIZE 8
#define KBD_BUFFER EP_DOUBLE_BUFFER
#define KBD_REPORT_KEYS (KBD_SIZE - 2)
// secondary keyboard
#ifdef USB_NKRO_ENABLE
#define KBD2_INTERFACE 4
#define KBD2_ENDPOINT 5
#define KBD2_SIZE 16
#define KBD2_BUFFER EP_DOUBLE_BUFFER
#define KBD2_REPORT_KEYS (KBD2_SIZE - 1)
#endif
#endif

View File

@ -1,4 +1,5 @@
#include <avr/interrupt.h>
#include "sendchar.h"
#include "usb_debug.h"
@ -7,8 +8,7 @@
volatile uint8_t debug_flush_timer=0;
// transmit a character. 0 returned on success, -1 on error
int8_t usb_debug_putchar(uint8_t c)
int8_t sendchar(uint8_t c)
{
static uint8_t previous_timeout=0;
uint8_t timeout, intr_state;
@ -60,7 +60,6 @@ int8_t usb_debug_putchar(uint8_t c)
return 0;
}
// immediately transmit any buffered output.
void usb_debug_flush_output(void)
{

View File

@ -14,7 +14,6 @@
extern volatile uint8_t debug_flush_timer;
int8_t usb_debug_putchar(uint8_t c); // transmit a character
void usb_debug_flush_output(void); // immediately transmit any buffered output
#endif

47
pjrc/usb_extra.c Normal file
View File

@ -0,0 +1,47 @@
#include <util/delay.h>
#include <avr/interrupt.h>
#include "host.h"
#include "usb_extra.h"
int8_t usb_extra_send(uint8_t report_id, uint16_t data)
{
uint8_t intr_state, timeout;
if (!usb_configured()) return -1;
intr_state = SREG;
cli();
UENUM = EXTRA_ENDPOINT;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = EXTRA_ENDPOINT;
}
UEDATX = report_id;
UEDATX = data&0xFF;
UEDATX = (data>>8)&0xFF;
UEINTX = 0x3A;
SREG = intr_state;
return 0;
}
int8_t usb_extra_consumer_send(uint16_t bits)
{
return usb_extra_send(REPORT_ID_CONSUMER, bits);
}
int8_t usb_extra_system_send(uint16_t bits)
{
return usb_extra_send(REPORT_ID_SYSTEM, bits);
}

23
pjrc/usb_extra.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef USB_EXTRA_H
#define USB_EXTRA_H 1
/*
* Enhanced keyboard features for Windows:
* Audio control and System control
*
* http://www.microsoft.com/whdc/archive/w2kbd.mspx
*/
#include <stdint.h>
#include "usb.h"
#define EXTRA_INTERFACE 3
#define EXTRA_ENDPOINT 4
#define EXTRA_SIZE 8
#define EXTRA_BUFFER EP_DOUBLE_BUFFER
int8_t usb_extra_consumer_send(uint16_t bits);
int8_t usb_extra_system_send(uint16_t bits);
#endif

97
pjrc/usb_keyboard.c Normal file
View File

@ -0,0 +1,97 @@
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "usb_keycodes.h"
#include "usb_keyboard.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "host.h"
// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
uint8_t usb_keyboard_protocol=1;
// the idle configuration, how often we send the report to the
// host (ms * 4) even when it hasn't changed
// Windows and Linux set 0 while OS X sets 6(24ms) by SET_IDLE request.
uint8_t usb_keyboard_idle_config=125;
// count until idle timeout
uint8_t usb_keyboard_idle_count=0;
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
volatile uint8_t usb_keyboard_leds=0;
static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end);
int8_t usb_keyboard_send_report(report_keyboard_t *report)
{
int8_t result = 0;
#ifdef USB_NKRO_ENABLE
if (keyboard_nkro)
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS);
else
#endif
{
if (usb_keyboard_protocol)
result = send_report(report, KBD_ENDPOINT, 0, KBD_REPORT_KEYS);
else
result = send_report(report, KBD_ENDPOINT, 0, 6);
}
if (result) return result;
usb_keyboard_idle_count = 0;
usb_keyboard_print_report(report);
return 0;
}
void usb_keyboard_print_report(report_keyboard_t *report)
{
if (!debug_keyboard) return;
print("keys: ");
for (int i = 0; i < REPORT_KEYS; i++) { phex(report->keys[i]); print(" "); }
print(" mods: "); phex(report->mods); print("\n");
}
static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end)
{
uint8_t intr_state, timeout;
if (!usb_configured()) return -1;
intr_state = SREG;
cli();
UENUM = endpoint;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = endpoint;
}
UEDATX = report->mods;
#ifdef USB_NKRO_ENABLE
if (!keyboard_nkro)
UEDATX = 0;
#else
UEDATX = 0;
#endif
for (uint8_t i = keys_start; i < keys_end; i++) {
UEDATX = report->keys[i];
}
UEINTX = 0x3A;
SREG = intr_state;
return 0;
}

19
pjrc/usb_keyboard.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef USB_KEYBOARD_H
#define USB_KEYBOARD_H 1
#include <stdint.h>
#include <stdbool.h>
#include "usb.h"
#include "host.h"
extern uint8_t usb_keyboard_protocol;
extern uint8_t usb_keyboard_idle_config;
extern uint8_t usb_keyboard_idle_count;
extern volatile uint8_t usb_keyboard_leds;
int8_t usb_keyboard_send_report(report_keyboard_t *report);
void usb_keyboard_print_report(report_keyboard_t *report);
#endif

58
pjrc/usb_mouse.c Normal file
View File

@ -0,0 +1,58 @@
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usb_mouse.h"
#include "print.h"
#include "debug.h"
uint8_t usb_mouse_protocol=1;
int8_t usb_mouse_send(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons)
{
uint8_t intr_state, timeout;
if (!usb_configured()) return -1;
if (x == -128) x = -127;
if (y == -128) y = -127;
if (wheel_v == -128) wheel_v = -127;
if (wheel_h == -128) wheel_h = -127;
intr_state = SREG;
cli();
UENUM = MOUSE_ENDPOINT;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = MOUSE_ENDPOINT;
}
UEDATX = buttons;
UEDATX = x;
UEDATX = y;
if (usb_mouse_protocol) {
UEDATX = wheel_v;
UEDATX = wheel_h;
}
UEINTX = 0x3A;
SREG = intr_state;
return 0;
}
void usb_mouse_print(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons) {
if (!debug_mouse) return;
print("usb_mouse[btn|x y v h]: ");
phex(buttons); print("|");
phex(x); print(" ");
phex(y); print(" ");
phex(wheel_v); print(" ");
phex(wheel_h); print("\n");
}

27
pjrc/usb_mouse.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef USB_MOUSE_H
#define USB_MOUSE_H 1
#include <stdint.h>
#include <stdbool.h>
#include "usb.h"
#define MOUSE_INTERFACE 1
#define MOUSE_ENDPOINT 2
#define MOUSE_SIZE 8
#define MOUSE_BUFFER EP_DOUBLE_BUFFER
#define MOUSE_BTN1 (1<<0)
#define MOUSE_BTN2 (1<<1)
#define MOUSE_BTN3 (1<<2)
#define MOUSE_BTN4 (1<<3)
#define MOUSE_BTN5 (1<<4)
extern uint8_t usb_mouse_protocol;
int8_t usb_mouse_send(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons);
void usb_mouse_print(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons);
#endif

30
print.c
View File

@ -1,17 +1,17 @@
/* Very basic print functions, intended to be used with usb_debug_only.c
* http://www.pjrc.com/teensy/
* Copyright (c) 2008 PJRC.COM, LLC
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -21,11 +21,11 @@
* THE SOFTWARE.
*/
// Version 1.0: Initial Release
//#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "print.h"
#include "sendchar.h"
bool print_enable = false;
@ -38,15 +38,25 @@ void print_P(const char *s)
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
if (c == '\n') usb_debug_putchar('\r');
usb_debug_putchar(c);
if (c == '\n') sendchar('\r');
sendchar(c);
}
}
void pdec(const int x)
{
if (!print_enable) return;
char ascii[32];
sprintf(ascii,"%i",x);
for (int i = 0; i < 32 && ascii[i] != 0; ++i) {
sendchar(ascii[i]);
}
}
void phex1(unsigned char c)
{
if (!print_enable) return;
usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10));
sendchar(c + ((c < 10) ? '0' : 'A' - 10));
}
void phex(unsigned char c)
@ -68,7 +78,7 @@ void pbin(unsigned char c)
{
if (!print_enable) return;
for (int i = 7; i >= 0; i--) {
usb_debug_putchar((c & (1<<i)) ? '1' : '0');
sendchar((c & (1<<i)) ? '1' : '0');
}
}
@ -76,6 +86,6 @@ void pbin_reverse(unsigned char c)
{
if (!print_enable) return;
for (int i = 0; i < 8; i++) {
usb_debug_putchar((c & (1<<i)) ? '1' : '0');
sendchar((c & (1<<i)) ? '1' : '0');
}
}

View File

@ -3,17 +3,16 @@
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "usb_debug.h"
bool print_enable;
extern bool print_enable;
// this macro allows you to write print("some text") and
// the string is automatically placed into flash memory :)
#define print(s) print_P(PSTR(s))
#define pchar(c) usb_debug_putchar(c)
void print_P(const char *s);
void pdec(const int x);
void phex(unsigned char c);
void phex16(unsigned int i);
void pbin(unsigned char c);

433
ps2.c Normal file
View File

@ -0,0 +1,433 @@
/*
Copyright (c) 2010,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 "ps2.h"
#include "debug.h"
static uint8_t recv_data(void);
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 inhibit(void);
/*
Primitive PS/2 Library for AVR
==============================
Host side is only supported now.
I/O control
-----------
High state is asserted by input with pull up.
PS/2 References
---------------
http://www.computer-engineering.org/ps2protocol/
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
*/
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
ps2_error = err; \
goto ERROR; \
} \
} while (0)
uint8_t ps2_error = PS2_ERR_NONE;
void ps2_host_init(void)
{
#ifdef PS2_INT_ENABLE
PS2_INT_ENABLE();
idle();
#else
inhibit();
#endif
}
// TODO: send using interrupt if available
uint8_t ps2_host_send(uint8_t data)
{
uint8_t res = 0;
bool parity = true;
ps2_error = PS2_ERR_NONE;
#ifdef PS2_INT_DISABLE
PS2_INT_DISABLE();
#endif
/* terminate a transmission if we have */
inhibit();
_delay_us(100);
/* start bit [1] */
data_lo();
clock_hi();
WAIT(clock_lo, 15000, 1);
/* data [2-9] */
for (uint8_t i = 0; i < 8; i++) {
_delay_us(15);
if (data&(1<<i)) {
parity = !parity;
data_hi();
} else {
data_lo();
}
WAIT(clock_hi, 50, 2);
WAIT(clock_lo, 50, 3);
}
/* parity [10] */
_delay_us(15);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_hi, 50, 4);
WAIT(clock_lo, 50, 5);
/* stop bit [11] */
_delay_us(15);
data_hi();
/* ack [12] */
WAIT(data_lo, 50, 6);
WAIT(clock_lo, 50, 7);
/* wait for idle state */
WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9);
res = ps2_host_recv_response();
ERROR:
#ifdef PS2_INT_ENABLE
PS2_INT_ENABLE();
idle();
#else
inhibit();
#endif
return res;
}
/* receive data when host want else inhibit communication */
uint8_t ps2_host_recv_response(void)
{
uint8_t data = 0;
/* terminate a transmission if we have */
inhibit();
_delay_us(100);
/* release lines(idle state) */
idle();
/* wait start bit */
wait_clock_lo(2000);
data = recv_data();
inhibit();
return data;
}
#ifndef PS2_INT_VECT
uint8_t ps2_host_recv(void)
{
return ps2_host_recv_response();
}
#else
/* ring buffer to store ps/2 key data */
#define PBUF_SIZE 8
static uint8_t pbuf[PBUF_SIZE];
static uint8_t pbuf_head = 0;
static uint8_t pbuf_tail = 0;
static inline void pbuf_enqueue(uint8_t data)
{
if (!data)
return;
uint8_t sreg = SREG;
cli();
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
if (next != pbuf_tail) {
pbuf[pbuf_head] = data;
pbuf_head = next;
} else {
debug("pbuf: full\n");
}
SREG = sreg;
}
static inline uint8_t pbuf_dequeue(void)
{
uint8_t val = 0;
uint8_t sreg = SREG;
cli();
if (pbuf_head != pbuf_tail) {
val = pbuf[pbuf_tail];
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
}
SREG = sreg;
return val;
}
/* get data received by interrupt */
uint8_t ps2_host_recv(void)
{
if (ps2_error) {
print("x");
phex(ps2_error);
ps2_host_send(0xFE); // request to resend
ps2_error = PS2_ERR_NONE;
}
idle();
return pbuf_dequeue();
}
#if 0
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
#define DEBUGP(x) do { PORTC = x; } while (0)
#else
#define DEBUGP_INIT()
#define DEBUGP(x)
#endif
ISR(PS2_INT_VECT)
{
static enum {
INIT,
START,
BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7,
PARITY,
STOP,
} state = INIT;
static uint8_t data = 0;
static uint8_t parity = 1;
// TODO: abort if elapse 100us from previous interrupt
// return unless falling edge
if (clock_in()) {
goto RETURN;
}
state++;
DEBUGP(state);
switch (state) {
case START:
if (data_in())
goto ERROR;
break;
case BIT0:
case BIT1:
case BIT2:
case BIT3:
case BIT4:
case BIT5:
case BIT6:
case BIT7:
data >>= 1;
if (data_in()) {
data |= 0x80;
parity++;
}
break;
case PARITY:
if (data_in()) {
if (!(parity & 0x01))
goto ERROR;
} else {
if (parity & 0x01)
goto ERROR;
}
break;
case STOP:
if (!data_in())
goto ERROR;
pbuf_enqueue(data);
goto DONE;
break;
default:
goto ERROR;
}
goto RETURN;
ERROR:
DEBUGP(0x0F);
inhibit();
ps2_error = state;
DONE:
state = INIT;
data = 0;
parity = 1;
RETURN:
return;
}
#endif
static void ps2_reset(void)
{
ps2_host_send(0xFF);
}
/* send LED state to keyboard */
void ps2_host_set_led(uint8_t led)
{
ps2_host_send(0xED);
ps2_host_send(led);
}
/* called after start bit comes */
static uint8_t recv_data(void)
{
uint8_t data = 0;
bool parity = true;
ps2_error = PS2_ERR_NONE;
/* start bit [1] */
WAIT(clock_lo, 1, 1);
WAIT(data_lo, 1, 2);
WAIT(clock_hi, 50, 3);
/* data [2-9] */
for (uint8_t i = 0; i < 8; i++) {
WAIT(clock_lo, 50, 4);
if (data_in()) {
parity = !parity;
data |= (1<<i);
}
WAIT(clock_hi, 50, 5);
}
/* parity [10] */
WAIT(clock_lo, 50, 6);
if (data_in() != parity) {
ps2_error = PS2_ERR_PARITY;
goto ERROR;
}
WAIT(clock_hi, 50, 7);
/* stop bit [11] */
WAIT(clock_lo, 50, 8);
WAIT(data_hi, 1, 9);
WAIT(clock_hi, 50, 10);
return data;
ERROR:
return 0;
}
static inline void clock_lo()
{
PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
}
static inline void clock_hi()
{
/* input with pull up */
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
}
static inline bool clock_in()
{
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
_delay_us(1);
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
}
static inline void data_lo()
{
PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
}
static inline void data_hi()
{
/* input with pull up */
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
}
static inline bool data_in()
{
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
_delay_us(1);
return PS2_DATA_PIN&(1<<PS2_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;
}
/* idle state that device can send */
static inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send */
static inline void inhibit(void)
{
clock_lo();
data_hi();
}

82
ps2.h Normal file
View File

@ -0,0 +1,82 @@
/*
Copyright (c) 2010,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 PS2_H
#define PS2_H
/*
* Primitive PS/2 Library for AVR
*/
/* port settings for clock and data line */
#if !(defined(PS2_CLOCK_PORT) && \
defined(PS2_CLOCK_PIN) && \
defined(PS2_CLOCK_DDR) && \
defined(PS2_CLOCK_BIT))
# error "PS/2 clock port setting is required in config.h"
#endif
#if !(defined(PS2_DATA_PORT) && \
defined(PS2_DATA_PIN) && \
defined(PS2_DATA_DDR) && \
defined(PS2_DATA_BIT))
# error "PS/2 data port setting is required in config.h"
#endif
#define PS2_ACK 0xFA
#define PS2_RESEND 0xFE
#define PS2_SET_LED 0xED
#define PS2_ERR_NONE 0
#define PS2_ERR_PARITY 0x10
#define PS2_LED_SCROLL_LOCK 0
#define PS2_LED_NUM_LOCK 1
#define PS2_LED_CAPS_LOCK 2
extern uint8_t ps2_error;
/* host role */
void ps2_host_init(void);
uint8_t ps2_host_send(uint8_t data);
uint8_t ps2_host_recv_response(void);
uint8_t ps2_host_recv(void);
void ps2_host_set_led(uint8_t usb_led);
/* device role */
#endif

201
ps2_mouse.c Normal file
View File

@ -0,0 +1,201 @@
#include <stdbool.h>
#include<avr/io.h>
#include<util/delay.h>
#include "ps2.h"
#include "ps2_mouse.h"
#include "usb_mouse.h"
#define PS2_MOUSE_DEBUG
#ifdef PS2_MOUSE_DEBUG
# include "print.h"
# include "debug.h"
#else
# define print(s)
# define phex(h)
# define phex16(h)
#endif
// disable when errors occur 255 times.
#define ERROR_RETURN() do { \
if (ps2_error) { \
if (ps2_mouse_error_count < 255) { \
ps2_mouse_error_count++; \
} else { \
ps2_mouse_error_count = 0; \
ps2_mouse_enable = false; \
} \
return ps2_error; \
} \
} while (0)
/*
TODO
----
- Stream mode
- Tracpoint command support: needed
- Middle button + move = Wheel traslation
*/
bool ps2_mouse_enable = true;
uint8_t ps2_mouse_x = 0;
uint8_t ps2_mouse_y = 0;
uint8_t ps2_mouse_btn = 0;
uint8_t ps2_mouse_error_count = 0;
static uint8_t ps2_mouse_btn_prev = 0;
uint8_t ps2_mouse_init(void) {
uint8_t rcv;
if (!ps2_mouse_enable) return 1;
ps2_host_init();
// Reset
rcv = ps2_host_send(0xFF);
print("ps2_mouse_init: send 0xFF: ");
phex(ps2_error); print("\n");
ERROR_RETURN();
// ACK
rcv = ps2_host_recv();
print("ps2_mouse_init: read ACK: ");
phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();
// BAT takes some time
_delay_ms(100);
rcv = ps2_host_recv();
print("ps2_mouse_init: read BAT: ");
phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();
// Device ID
rcv = ps2_host_recv();
print("ps2_mouse_init: read DevID: ");
phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();
// Enable data reporting
ps2_host_send(0xF4);
print("ps2_mouse_init: send 0xF4: ");
phex(ps2_error); print("\n");
ERROR_RETURN();
// ACK
rcv = ps2_host_recv();
print("ps2_mouse_init: read ACK: ");
phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();
// Set Remote mode
ps2_host_send(0xF0);
print("ps2_mouse_init: send 0xF0: ");
phex(ps2_error); print("\n");
ERROR_RETURN();
// ACK
rcv = ps2_host_recv();
print("ps2_mouse_init: read ACK: ");
phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();
return 0;
}
/*
Data format:
bit: 7 6 5 4 3 2 1 0
-----------------------------------------------------------------------
0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left
1 x: X movement(0-255)
2 y: Y movement(0-255)
*/
uint8_t ps2_mouse_read(void)
{
uint8_t rcv;
if (!ps2_mouse_enable) return 1;
ps2_host_send(0xEB);
ERROR_RETURN();
rcv=ps2_host_recv();
ERROR_RETURN();
if(rcv==0xFA) {
ps2_mouse_btn = ps2_host_recv();
ERROR_RETURN();
ps2_mouse_x = ps2_host_recv();
ERROR_RETURN();
ps2_mouse_y = ps2_host_recv();
ERROR_RETURN();
}
return 0;
}
bool ps2_mouse_changed(void)
{
return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev);
}
#define PS2_MOUSE_SCROLL_BUTTON 0x04
void ps2_mouse_usb_send(void)
{
static bool scrolled = false;
if (!ps2_mouse_enable) return;
if (ps2_mouse_changed()) {
int8_t x, y, v, h;
x = y = v = h = 0;
// convert scale of X, Y: PS/2(-256/255) -> USB(-127/127)
if (ps2_mouse_btn & (1<<PS2_MOUSE_X_SIGN))
x = ps2_mouse_x > 128 ? (int8_t)ps2_mouse_x : -127;
else
x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127;
if (ps2_mouse_btn & (1<<PS2_MOUSE_Y_SIGN))
y = ps2_mouse_y > 128 ? (int8_t)ps2_mouse_y : -127;
else
y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127;
// Y is needed to reverse
y = -y;
if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) {
// scroll
if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x));
if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y));
if (h || v) {
scrolled = true;
usb_mouse_send(0,0, -v/16, h/16, 0);
_delay_ms(100);
}
} else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) {
usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON);
_delay_ms(100);
usb_mouse_send(0,0,0,0, 0);
} else {
scrolled = false;
usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
}
ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
ps2_mouse_print();
}
ps2_mouse_x = 0;
ps2_mouse_y = 0;
ps2_mouse_btn = 0;
}
void ps2_mouse_print(void)
{
if (!debug_mouse) return;
print("ps2_mouse[btn|x y]: ");
phex(ps2_mouse_btn); print("|");
phex(ps2_mouse_x); print(" ");
phex(ps2_mouse_y); print("\n");
}

27
ps2_mouse.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef PS2_MOUSE_H
#define PS2_MOUSE_H
#include <stdbool.h>
#define PS2_MOUSE_BTN_MASK 0x07
#define PS2_MOUSE_BTN_LEFT 0
#define PS2_MOUSE_BTN_RIGHT 1
#define PS2_MOUSE_BTN_MIDDLE 2
#define PS2_MOUSE_X_SIGN 4
#define PS2_MOUSE_Y_SIGN 5
#define PS2_MOUSE_X_OVFLW 6
#define PS2_MOUSE_Y_OVFLW 7
bool ps2_mouse_enable;
extern uint8_t ps2_mouse_x;
extern uint8_t ps2_mouse_y;
extern uint8_t ps2_mouse_btn;
extern uint8_t ps2_mouse_error_count;
uint8_t ps2_mouse_init(void);
uint8_t ps2_mouse_read(void);
bool ps2_mouse_changed(void);
void ps2_mouse_usb_send(void);
void ps2_mouse_print(void);
#endif

325
ps2_usart.c Normal file
View File

@ -0,0 +1,325 @@
/*
Copyright (c) 2010,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.
*/
/*
Primitive PS/2 Library for AVR
==============================
Host side is only supported now.
Synchronous USART is used to receive data by hardware process
rather than interrupt. During V-USB interrupt runs, CLOCK interrupt
cannot interpose. In the result it is prone to lost CLOCK edge.
I/O control
-----------
High state is asserted by internal pull-up.
If you have a signaling problem, you may need to have
external pull-up resisters on CLOCK and DATA line.
PS/2 References
---------------
http://www.computer-engineering.org/ps2protocol/
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
*/
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "ps2.h"
#include "debug.h"
#if 0
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
#define DEBUGP(x) do { PORTC = x; } while (0)
#else
#define DEBUGP_INIT()
#define DEBUGP(x)
#endif
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
ps2_error = err; \
goto ERROR; \
} \
} while (0)
uint8_t ps2_error = PS2_ERR_NONE;
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 inhibit(void);
#if defined PS2_USE_INT || defined PS2_USE_USART
static inline uint8_t pbuf_dequeue(void);
static inline void pbuf_enqueue(uint8_t data);
#endif
void ps2_host_init(void)
{
DEBUGP_INIT();
DEBUGP(0x1);
idle();
PS2_USART_INIT();
PS2_USART_RX_INT_ON();
}
uint8_t ps2_host_send(uint8_t data)
{
uint8_t res = 0;
bool parity = true;
ps2_error = PS2_ERR_NONE;
DEBUGP(0x6);
PS2_USART_OFF();
/* terminate a transmission if we have */
inhibit();
_delay_us(100);
/* start bit [1] */
data_lo();
clock_hi();
WAIT(clock_lo, 15000, 1);
/* data [2-9] */
for (uint8_t i = 0; i < 8; i++) {
_delay_us(15);
if (data&(1<<i)) {
parity = !parity;
data_hi();
} else {
data_lo();
}
WAIT(clock_hi, 50, 2);
WAIT(clock_lo, 50, 3);
}
/* parity [10] */
_delay_us(15);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_hi, 50, 4);
WAIT(clock_lo, 50, 5);
/* stop bit [11] */
_delay_us(15);
data_hi();
/* ack [12] */
WAIT(data_lo, 50, 6);
WAIT(clock_lo, 50, 7);
/* wait for idle state */
WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9);
res = ps2_host_recv_response();
ERROR:
idle();
PS2_USART_INIT();
PS2_USART_RX_INT_ON();
return res;
}
// Do polling data from keyboard to get response to last command.
uint8_t ps2_host_recv_response(void)
{
uint8_t data = 0;
PS2_USART_INIT();
PS2_USART_RX_POLL_ON();
while (!PS2_USART_RX_READY)
;
data = PS2_USART_RX_DATA;
PS2_USART_OFF();
DEBUGP(0x9);
return data;
}
uint8_t ps2_host_recv(void)
{
return pbuf_dequeue();
}
ISR(PS2_USART_RX_VECT)
{
DEBUGP(0x7);
uint8_t error = PS2_USART_ERROR;
uint8_t data = PS2_USART_RX_DATA;
if (error) {
DEBUGP(error>>2);
} else {
pbuf_enqueue(data);
}
DEBUGP(0x8);
}
/* send LED state to keyboard */
void ps2_host_set_led(uint8_t led)
{
// send 0xED then keyboard keeps waiting for next LED data
// and keyboard does not send any scan codes during waiting.
// If fail to send LED data keyboard looks like being freezed.
uint8_t retry = 3;
while (retry-- && ps2_host_send(PS2_SET_LED) != PS2_ACK)
;
retry = 3;
while (retry-- && ps2_host_send(led) != PS2_ACK)
;
}
/*--------------------------------------------------------------------
* static functions
*------------------------------------------------------------------*/
static inline void clock_lo()
{
PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
}
static inline void clock_hi()
{
/* input with pull up */
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
}
static inline bool clock_in()
{
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
_delay_us(1);
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
}
static inline void data_lo()
{
PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
}
static inline void data_hi()
{
/* input with pull up */
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
}
static inline bool data_in()
{
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
_delay_us(1);
return PS2_DATA_PIN&(1<<PS2_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;
}
/* idle state that device can send */
static inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send */
static inline void inhibit(void)
{
clock_lo();
data_hi();
}
/*--------------------------------------------------------------------
* Ring buffer to store scan codes from keyboard
*------------------------------------------------------------------*/
#define PBUF_SIZE 8
static uint8_t pbuf[PBUF_SIZE];
static uint8_t pbuf_head = 0;
static uint8_t pbuf_tail = 0;
static inline void pbuf_enqueue(uint8_t data)
{
if (!data)
return;
uint8_t sreg = SREG;
cli();
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
if (next != pbuf_tail) {
pbuf[pbuf_head] = data;
pbuf_head = next;
} else {
debug("pbuf: full\n");
}
SREG = sreg;
}
static inline uint8_t pbuf_dequeue(void)
{
uint8_t val = 0;
uint8_t sreg = SREG;
cli();
if (pbuf_head != pbuf_tail) {
val = pbuf[pbuf_tail];
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
}
SREG = sreg;
return val;
}

56
ps2_usb/Makefile Normal file
View File

@ -0,0 +1,56 @@
#
# Makefile for PJRC Teensy
#
# Target file name (without extension).
TARGET = ps2_usb_pjrc
# Directory common source filess exist
COMMON_DIR = ..
# Directory keyboard dependent files exist
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = main_pjrc.c \
keymap.c \
matrix.c \
led.c \
ps2.c
CONFIG_H = config_pjrc.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
USB_EXTRA_ENABLE = yes # Audio control and System control
USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
include $(COMMON_DIR)/Makefile.pjrc
include $(COMMON_DIR)/Makefile.common

89
ps2_usb/Makefile.vusb Normal file
View File

@ -0,0 +1,89 @@
#
# Makefile for V-USB
#
# Target file name (without extension).
TARGET = ps2_usb_vusb
# Directory common source filess exist
COMMON_DIR = ..
# Directory keyboard dependent files exist
TARGET_DIR = .
# keyboard dependent files
TARGET_SRC = main_vusb.c \
keymap.c \
matrix.c \
led.c \
ps2_usart.c
CONFIG_H = config_vusb.h
# V-USB debug level: To use ps2_usart.c level must be 0
# ps2_usart.c requires USART to receive PS/2 signal.
OPT_DEFS = -DDEBUG_LEVEL=0
# 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
MCU = atmega168
# 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 = 20000000
# Build Options
# comment out to disable the options.
#
MOUSEKEY_ENABLE = yes # Mouse keys
USB_EXTRA_ENABLE = yes # Audio control and System control
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
#---------------- Programming Options --------------------------
AVRDUDE = avrdude
# Type: avrdude -c ? to get a full listing.
AVRDUDE_PROGRAMMER = usbasp
AVRDUDE_PORT =
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS = -p $(MCU) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
PROGRAM_CMD = $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
include $(COMMON_DIR)/Makefile.vusb
include $(COMMON_DIR)/Makefile.common

173
ps2_usb/README Normal file
View File

@ -0,0 +1,173 @@
PS/2 to USB Dvorak/Qwerty keyboard converter
==============================
This firmware converts PS/2 keyboard protocol to USB,
and is specially suited for users who use the Dvorak
keyboard layout, but want to easily switch between
layouts and keep Qwerty shortcuts (like Ctrl+c).
Demostration build
------------------
In this demo build, you can try several layouts,
mouse keys and USB NKRO.
Special keys:
Magic+0: Dvorak (default)
Magic+1: Qwerty
Magic+2: Dvorak with mouse keys
Magic+3: Qwerty with mouse keys
Magic+N: toggles NKRO/6KRO(6KRO by default)
Magic+Esc: sends Power Event
where Magic=(LShift+RShift)
LCtrl+LShift+RCtrl+RShift swaps between layout
0 (Dvorak) and 1 (Qwerty), the scroll lock LED,
and the LED on the Teensy indicates this change
by being on for Qwerty, and off for Dvorak.
Keybinds: (keys are specified in qwerty layout)
Fn0+(hjkl): Mouse key move(vi cursor)
Fn0+(yuio): Mouse wheel(left,down,up,right)
Fn0+space: Mouse button1
Fn0+(mnb): Mouse buttons(1,2,3)
Fn0+(zxc): Media control(Volup, Voldown, Mute)
Fn1+(hjkl): Cursor move(vi cursor)
Fn1+(nm,.): Cursor move(Home,PageDown,PageUp,End)
Fn2+(esdf): Mouse key move(invert T cursor)
Fn2+(qwrt): Mouse wheel(left,down,up,right)
Fn2+space: Mouse button1
Fn2+(,./): Media control(Volup, Voldown, Mute)
where Fn0=;, Fn1=/, Fn2=a
Features
--------
Mouse keys
You can emulates mouse move and button click using keyboard.
System/Media control
You can sends Power event, Volume down/up and Mute.
USB NKRO(actually 120KRO+8Modifiers)
You can tolggles NKRO/6KRO.(Not tested on Mac.)
Keymap customization
You can customize keymaps easily by editing source code.
Build for Teensy
----------------
0. Connect PS/2 keyboard to Teensy by 4 lines(Vcc, GND, Data, Clock).
1. Define following macros for PS/2 connection in config_pjrc.h:
PS2_DATA_PORT
PS2_DATA_PIN
PS2_DATA_DDR
PS2_DATA_BIT
PS2_CLOCK_PORT
PS2_CLOCK_PIN
PS2_CLOCK_DDR
PS2_CLOCK_BIT
2. Edit Makefile for build options and MCU setting.
2. make
3. program Teensy.
http://www.pjrc.com/teensy/loader.html
Build for V-USB
---------------
0. Build V-USB controller board and connect PS/2 keyboard.
1. Define macros in config_vusb.h if needed.
2. Edit Makefile.vusb for build options and MCU setting.
3. make -f Makefile.vusb
4. program your V-USB controller.
V-USB Circuit
-------------
+---+ +---------------+
USB GND | | ATmega168 |
=== C3 | |
5V <-------+--------+---|Vcc,AVCC | PS/2
R1 | | ====
D- <----+--+-----R2-----|INT1 RXD|------->DATA
D+ <----|---+----R3-----|INT0 XCK|------->CLOCK
Z1 Z2 | | ->5V
GND<----+---+--+--+-----|GND | ->GND
| | | |
| C2-+--|XTAL1 |
| X1 | |
+--C3-+--|XTAL2 |
+---------------+
R1: 1.5K Ohm
R2,R3: 68 Ohm
Z1,Z2: Zenner 3.6V
C1,C2: 22pF
C3: 0.1uF
X1: Crystal 20MHz(16MHz/12MHz)
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.
If you want to define more than one keymap, see hhkb/keymap.c and
macway/keymap.c as examples. To define keymap(layer) switching may
needs a bit of your effort at this time.
/* Default Layer: plain keymap
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------.
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak|
* `---' `---------------' `---------------' `---------------' `-----------' `-----------'
* ,-----------------------------------------------------------. ,-----------. ,---------------.
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| /| *| -|
* |-----------------------------------------------------------| |-----------| |---------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| |
* |-----------------------------------------------------------| `-----------' |-----------| +|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| |
* |-----------------------------------------------------------| ,---. |---------------|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
* |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| |
* `-----------------------------------------------------------' `-----------' `---------------'
*/
KEYMAP(
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR, F13, F14,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
),
Multimedia keys
---------------
Following lists PS/2 special keys supported by Windows.
http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx
Key PS/2(Set2) HID
---------------------------------------------------
System Power E0 37 01 0081
System Sleep E0 3F 01 0082
System Wake E0 5E 01 0083
System Mute E0 23 0C 00E2
Volume Up E0 32 0C 00E9
Volume Down E0 21 0C 00EA
Scan Next Track E0 4D 0C 00B5
Scan Previous Track E0 15 0C 00B6
Stop E0 3B 0C 00B7
Play/Pause E0 34 0C 00CD
Media Select E0 50 0C 0183
Mail E0 48 0C 018A
Calculator E0 2B 0C 0192
My Computer E0 40 0C 0194
WWW Search E0 10 0C 0221
WWW Home E0 3A 0C 0223
WWW Back E0 38 0C 0224
WWW Forward E0 30 0C 0225
WWW Stop E0 28 0C 0226
WWW Refresh E0 20 0C 0227
WWW Favorites E0 18 0C 022A
EOF

Some files were not shown because too many files have changed in this diff Show More