diff options
Diffstat (limited to 'converter/adb_usb')
-rw-r--r-- | converter/adb_usb/Makefile.blargg | 131 | ||||
-rw-r--r-- | converter/adb_usb/adb_blargg.c | 216 | ||||
-rw-r--r-- | converter/adb_usb/adb_blargg.h | 38 |
3 files changed, 385 insertions, 0 deletions
diff --git a/converter/adb_usb/Makefile.blargg b/converter/adb_usb/Makefile.blargg new file mode 100644 index 0000000000..edce82d695 --- /dev/null +++ b/converter/adb_usb/Makefile.blargg @@ -0,0 +1,131 @@ +#---------------------------------------------------------------------------- +# 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. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# 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". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = adb_usb_blargg + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = keymap.c \ + matrix.c \ + led.c \ + adb_blargg.c + +CONFIG_H = config.h + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/adb_usb/adb_blargg.c b/converter/adb_usb/adb_blargg.c new file mode 100644 index 0000000000..963758c533 --- /dev/null +++ b/converter/adb_usb/adb_blargg.c @@ -0,0 +1,216 @@ +// Bit-banged implementation without any use of interrupts. +// Data pin must have external 1K pull-up resistor. +// Operates data pin as open-collector output. + +#include "adb_blargg.h" + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> + +// Copyright 2011 Jun WAKO <wakojun@gmail.com> +// Copyright 2013 Shay Green <gblargg@gmail.com> +// See bottom of file for license + +typedef uint8_t byte; + +// Make loop iteration take us total, including cyc overhead of loop logic +#define delay_loop_usec( us, cyc ) \ + __builtin_avr_delay_cycles( (unsigned long) (F_CPU / 1e6 * (us) + 0.5) - (cyc) ) + +#if !defined(ADB_PORT) || \ + !defined(ADB_PIN) || \ + !defined(ADB_DDR) || \ + !defined(ADB_DATA_BIT) + #error +#endif + +enum { data_mask = 1<<ADB_DATA_BIT }; + +enum { adb_cmd_read = 0x2C }; +enum { adb_cmd_write = 0x28 }; + +// gcc is very unreliable for inlining, so use macros +#define data_lo() (ADB_DDR |= data_mask) +#define data_hi() (ADB_DDR &= ~data_mask) +#define data_in() (ADB_PIN & data_mask) + +static void place_bit( byte bit ) +{ + // 100 us bit cell time + data_lo(); + _delay_us( 35 ); + + // Difference between a 0 and 1 bit is just this 30us portion in the middle + if ( bit ) + data_hi(); + _delay_us( 30 ); + + data_hi(); + _delay_us( 35 ); +} + +static void place_bit0( void ) { place_bit( 0 ); } +static void place_bit1( void ) { place_bit( 1 ); } + +static void send_byte( byte data ) +{ + for ( byte n = 8; n; n-- ) + { + place_bit( data & 0x80 ); + data <<= 1; + } +} + +static void command( byte cmd ) +{ + data_lo(); + _delay_us( 800 ); + place_bit1(); + send_byte( cmd ); + place_bit0(); +} + +void adb_host_init( void ) +{ + // Always keep port output 0, then just toggle DDR to be GND or leave it floating (high). + ADB_DDR &= ~data_mask; + ADB_PORT &= ~data_mask; + + #ifdef ADB_PSW_BIT + // Weak pull-up + ADB_PORT |= (1<<ADB_PSW_BIT); + ADB_DDR &= ~(1<<ADB_PSW_BIT); + #endif +} + +bool adb_host_psw( void ) +{ + #ifdef ADB_PSW_BIT + return (ADB_PIN & (1<<ADB_PSW_BIT)) != 0; + #else + return true; + #endif +} + +// Waits while data == val, or until us timeout expires. Returns remaining time, +// zero if timed out. +static byte while_data( byte us, byte data ) +{ + while ( data_in() == data ) + { + delay_loop_usec( 1 /* us period */, 7 /* cycles loop overhead */ ); + if ( !--us ) + break; + } + return us; +} + +static byte while_lo( byte us ) { return while_data( us, 0 ); } +static byte while_hi( byte us ) { return while_data( us, data_mask ); } + +static uint16_t adb_host_talk( byte cmd ) +{ + command( cmd ); + _delay_us( 5 ); + if ( !while_hi( 260 - 5 ) ) // avg 160 + return adb_host_nothing; + + // Receive start bit and 16 data bits. + // Doing them all in loop allows consistent error checking + uint16_t data = 0; + byte n = 17; + do + { + data <<= 1; + enum { timeout = 130 }; // maximum bit cell time + + byte lo = while_lo( timeout ); + if ( !lo ) + goto error; // timeout + + byte hi = while_hi( lo ); + if ( !hi ) + goto error; // timeout + + if ( timeout-lo < lo-hi ) + data |= 1; + else if ( n == 17 ) + goto error; // start bit is wrong + } + while ( --n ); + + // duration must be split in two due to 255 limit + if ( !while_lo( 255 ) && !while_lo( 351 - 255 ) ) + goto error; + + if ( while_hi( 91 ) ) + goto error; + + return data; + +error: + return adb_host_error; +} + +uint16_t adb_host_kbd_recv( void ) +{ + return adb_host_talk( adb_cmd_read + 0 ); +} + +uint16_t adb_host_kbd_modifiers( void ) +{ + return adb_host_talk( adb_cmd_read + 2 ); +} + +void adb_host_listen( byte cmd, byte data_h, byte data_l ) +{ + command( cmd ); + _delay_us( 200 ); + + place_bit1(); + send_byte( data_h ); + send_byte( data_l ); + place_bit0(); +} + +void adb_host_kbd_led( byte led ) +{ + adb_host_listen( adb_cmd_write + 2, 0, led & 0x07 ); +} + +/* 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. */ diff --git a/converter/adb_usb/adb_blargg.h b/converter/adb_usb/adb_blargg.h new file mode 100644 index 0000000000..2542cb5496 --- /dev/null +++ b/converter/adb_usb/adb_blargg.h @@ -0,0 +1,38 @@ +// Basic support for ADB keyboard + +#ifndef ADB_BLARGG_H +#define ADB_BLARGG_H + +#include <stdint.h> +#include <stdbool.h> + +// Sets up ADB bus. Doesn't send anything to keyboard. +void adb_host_init( void ); + +// Receives key press event from keyboard. +// 0xKKFF: one key changed state +// 0xKKKK: two keys changed state +enum { adb_host_nothing = 0 }; // no keys changed state +enum { adb_host_error = 0xFFFE }; // receive error +uint16_t adb_host_kbd_recv( void ); + +// Current state of keyboard modifiers and a few other keys +// Returns adb_host_nothing if keyboard didn't respond. +// Returns adb_host_error if error receiving. +uint16_t adb_host_kbd_modifiers( void ); + +// Sends command and two bytes of data to keyboard +void adb_host_listen( uint8_t cmd, uint8_t data_h, uint8_t data_l ); + +// Sets keyboard LEDs. Note that bits are inverted here, so 1 means off, 0 means on. +void adb_host_kbd_led( uint8_t led ); + +// State of power switch (false = pressed), or true if unsupported +bool adb_host_psw( void ); + + +// Legacy support +#define ADB_POWER 0x7F +#define ADB_CAPS 0x39 + +#endif |