From 47f5d8b545eec12ca74d8e7048bb5daa290d937e Mon Sep 17 00:00:00 2001 From: tmk Date: Sun, 20 Feb 2011 17:46:02 +0900 Subject: [PATCH] Synchronous USART support for PS/2 on V-USB stack --- Makefile.rules | 36 ----- ps2.h | 4 + ps2_vusb/Makefile | 37 ++++- ps2_vusb/config.h | 88 ++++++++--- ps2_vusb/main.c | 54 +++---- ps2_vusb/ps2_usart.c | 325 ++++++++++++++++++++++++++++++++++++++ ps2_vusb/sendchar_dummy.c | 8 + ps2_vusb/sendchar_usart.c | 58 +++++++ ps2_vusb/usart_print.c | 53 ------- ps2_vusb/usart_print.h | 121 -------------- ps2_vusb/usbconfig.h | 12 +- 11 files changed, 527 insertions(+), 269 deletions(-) create mode 100644 ps2_vusb/ps2_usart.c create mode 100644 ps2_vusb/sendchar_dummy.c create mode 100644 ps2_vusb/sendchar_usart.c delete mode 100644 ps2_vusb/usart_print.c delete mode 100644 ps2_vusb/usart_print.h diff --git a/Makefile.rules b/Makefile.rules index 77bdf884..96d1d7e1 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -233,42 +233,6 @@ LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) -#---------------- 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 -# 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. diff --git a/ps2.h b/ps2.h index 7a8bbd26..a821acde 100644 --- a/ps2.h +++ b/ps2.h @@ -56,6 +56,10 @@ POSSIBILITY OF SUCH DAMAGE. # 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 diff --git a/ps2_vusb/Makefile b/ps2_vusb/Makefile index 406008d8..6901d1f5 100644 --- a/ps2_vusb/Makefile +++ b/ps2_vusb/Makefile @@ -12,8 +12,9 @@ TARGET_SRC = main.c \ keymap.c \ matrix.c \ led.c \ - ps2.c \ - usart_print.c + ps2_usart.c \ + sendchar_dummy.c +# sendchar_usart.c OPT_DEFS = -DDEBUG_LEVEL=0 @@ -32,7 +33,7 @@ MCU = atmega168 # 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 +F_CPU = 20000000 # Build Options @@ -43,5 +44,35 @@ MOUSEKEY_ENABLE = yes # Mouse keys #USB_NKRO_ENABLE = yes # USB Nkey Rollover + +#---------------- Programming Options (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 +# 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) + + + include $(COMMON_DIR)/Makefile.vusb include $(COMMON_DIR)/Makefile.common diff --git a/ps2_vusb/config.h b/ps2_vusb/config.h index 858fe883..9447dd93 100644 --- a/ps2_vusb/config.h +++ b/ps2_vusb/config.h @@ -3,7 +3,9 @@ #define VENDOR_ID 0xFEED -#define PRODUCT_ID 0x6512 +#define PRODUCT_ID 0x2233 +// TODO: share these strings with usbconfig.h +// Edit usbconfig.h to change these. #define MANUFACTURER t.m.k. #define PRODUCT PS/2 keyboard converter #define DESCRIPTION convert PS/2 keyboard to USB @@ -33,36 +35,84 @@ #define PS2_CLOCK_PORT PORTD #define PS2_CLOCK_PIN PIND #define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 3 +#define PS2_CLOCK_BIT 4 #define PS2_DATA_PORT PORTD #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD -#define PS2_DATA_BIT 7 +#define PS2_DATA_BIT 0 -/* External interrupt for PS/2 clock line (optional) */ -#define PS2_INT_ENABLE() do { \ - EIMSK |= (1< -#include #include -#include /* for sei() */ -#include /* required by usbdrv.h */ -#include /* for _delay_ms() */ +#include +#include #include "usbdrv.h" -#include "usart_print.h" /* This is also an example for using debug macros */ -#include "usb_keycodes.h" -#include "matrix_skel.h" -#include "keymap_skel.h" -#include "mousekey.h" -#include "layer.h" -#include "print.h" -#include "debug.h" -#include "sendchar.h" -#include "host.h" +#include "oddebug.h" #include "host_vusb.h" -#include "timer.h" -#include "led.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 + -//static uint8_t last_led = 0; int main(void) { DEBUGP_INIT(); wdt_enable(WDTO_1S); - /* Even if you don't use the watchdog, turn it off here. On newer devices, - * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! - */ - - /* RESET status: all port bits are inputs without pull-up. - * That's the way we need D+ and D-. Therefore we don't need any - * additional hardware initialization. - */ odDebugInit(); usbInit(); - print_enable = true; - debug_enable = true; - keyboard_init(); - /* enforce re-enumeration, do this while interrupts are disabled! */ usbDeviceDisconnect(); uint8_t i = 0; - while(--i){ /* fake USB disconnect for > 250 ms */ + /* fake USB disconnect for > 250 ms */ + while(--i){ wdt_reset(); _delay_ms(1); } usbDeviceConnect(); sei(); - //uint8_t fn_bits = 0; - while (1) { /* main event loop */ + keyboard_init(); + + while (1) { + DEBUGP(0x1); wdt_reset(); usbPoll(); + DEBUGP(0x2); keyboard_proc(); + DEBUGP(0x3); host_vusb_keyboard_send(); } } diff --git a/ps2_vusb/ps2_usart.c b/ps2_vusb/ps2_usart.c new file mode 100644 index 00000000..e45b94c9 --- /dev/null +++ b/ps2_vusb/ps2_usart.c @@ -0,0 +1,325 @@ +/* +Copyright (c) 2010,2011 Jun WAKO + +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 +#include +#include +#include +#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<>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< +#include "sendchar.h" + + +int8_t sendchar(uint8_t c) +{ + return 1; +} diff --git a/ps2_vusb/sendchar_usart.c b/ps2_vusb/sendchar_usart.c new file mode 100644 index 00000000..fe18177a --- /dev/null +++ b/ps2_vusb/sendchar_usart.c @@ -0,0 +1,58 @@ +#include +#include "oddebug.h" +#include "sendchar.h" + + +/* from oddebug.h */ +#if defined UBRR +# define ODDBG_UBRR UBRR +#elif defined UBRRL +# define ODDBG_UBRR UBRRL +#elif defined UBRR0 +# define ODDBG_UBRR UBRR0 +#elif defined UBRR0L +# define ODDBG_UBRR UBRR0L +#endif + +#if defined UCR +# define ODDBG_UCR UCR +#elif defined UCSRB +# define ODDBG_UCR UCSRB +#elif defined UCSR0B +# define ODDBG_UCR UCSR0B +#endif + +#if defined TXEN +# define ODDBG_TXEN TXEN +#else +# define ODDBG_TXEN TXEN0 +#endif + +#if defined USR +# define ODDBG_USR USR +#elif defined UCSRA +# define ODDBG_USR UCSRA +#elif defined UCSR0A +# define ODDBG_USR UCSR0A +#endif + +#if defined UDRE +# define ODDBG_UDRE UDRE +#else +# define ODDBG_UDRE UDRE0 +#endif + +#if defined UDR +# define ODDBG_UDR UDR +#elif defined UDR0 +# define ODDBG_UDR UDR0 +#endif + + +/* from oddebug.c */ +int8_t sendchar(uint8_t c) +{ + while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ + ODDBG_UDR = c; + return 1; +} diff --git a/ps2_vusb/usart_print.c b/ps2_vusb/usart_print.c deleted file mode 100644 index 2dfc949b..00000000 --- a/ps2_vusb/usart_print.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Name: oddebug.c - * Project: AVR library - * Author: Christian Starkjohann - * Creation Date: 2005-01-16 - * 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: oddebug.c 692 2008-11-07 15:07:40Z cs $ - */ - -#include "usart_print.h" -#include "sendchar.h" - - -int8_t sendchar(uint8_t c) -{ - while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ - ODDBG_UDR = c; - return 0; -} - -void uartPutc(char c) -{ - while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ - ODDBG_UDR = c; -} - -static uchar hexAscii(uchar h) -{ - h &= 0xf; - if(h >= 10) - h += 'a' - (uchar)10 - '0'; - h += '0'; - return h; -} - -void printHex(uchar c) -{ - uartPutc(hexAscii(c >> 4)); - uartPutc(hexAscii(c)); -} - -void odDebug(uchar prefix, uchar *data, uchar len) -{ - printHex(prefix); - uartPutc(':'); - while(len--){ - uartPutc(' '); - printHex(*data++); - } - uartPutc('\r'); - uartPutc('\n'); -} diff --git a/ps2_vusb/usart_print.h b/ps2_vusb/usart_print.h deleted file mode 100644 index e6e83a08..00000000 --- a/ps2_vusb/usart_print.h +++ /dev/null @@ -1,121 +0,0 @@ -/* Name: oddebug.h - * Project: AVR library - * Author: Christian Starkjohann - * Creation Date: 2005-01-16 - * 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: oddebug.h 692 2008-11-07 15:07:40Z cs $ - */ - -#ifndef __oddebug_h_included__ -#define __oddebug_h_included__ - -/* -General Description: -This module implements a function for debug logs on the serial line of the -AVR microcontroller. Debugging can be configured with the define -'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging -calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is -2, DBG1 and DBG2 logs will be printed. - -A debug log consists of a label ('prefix') to indicate which debug log created -the output and a memory block to dump in hex ('data' and 'len'). -*/ - - -#ifndef F_CPU -# define F_CPU 12000000 /* 12 MHz */ -#endif - -/* make sure we have the UART defines: */ -#include "usbportability.h" - -#ifndef uchar -# define uchar unsigned char -#endif - -#if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ -# warning "Debugging disabled because device has no UART" -# undef DEBUG_LEVEL -#endif - -#ifndef DEBUG_LEVEL -# define DEBUG_LEVEL 0 -#endif - -/* ------------------------------------------------------------------------- */ - -#if DEBUG_LEVEL > 0 -# define DBG1(prefix, data, len) odDebug(prefix, data, len) -#else -# define DBG1(prefix, data, len) -#endif - -#if DEBUG_LEVEL > 1 -# define DBG2(prefix, data, len) odDebug(prefix, data, len) -#else -# define DBG2(prefix, data, len) -#endif - -/* ------------------------------------------------------------------------- */ - -extern void odDebug(uchar prefix, uchar *data, uchar len); -void uartPutc(char c); -void printHex(uchar c); - -/* Try to find our control registers; ATMEL likes to rename these */ - -#if defined UBRR -# define ODDBG_UBRR UBRR -#elif defined UBRRL -# define ODDBG_UBRR UBRRL -#elif defined UBRR0 -# define ODDBG_UBRR UBRR0 -#elif defined UBRR0L -# define ODDBG_UBRR UBRR0L -#endif - -#if defined UCR -# define ODDBG_UCR UCR -#elif defined UCSRB -# define ODDBG_UCR UCSRB -#elif defined UCSR0B -# define ODDBG_UCR UCSR0B -#endif - -#if defined TXEN -# define ODDBG_TXEN TXEN -#else -# define ODDBG_TXEN TXEN0 -#endif - -#if defined USR -# define ODDBG_USR USR -#elif defined UCSRA -# define ODDBG_USR UCSRA -#elif defined UCSR0A -# define ODDBG_USR UCSR0A -#endif - -#if defined UDRE -# define ODDBG_UDRE UDRE -#else -# define ODDBG_UDRE UDRE0 -#endif - -#if defined UDR -# define ODDBG_UDR UDR -#elif defined UDR0 -# define ODDBG_UDR UDR0 -#endif - -static inline void odDebugInit(void) -{ - ODDBG_UCR |= (1<> 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! @@ -225,7 +227,7 @@ section at the end of this file). * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand * the implications! */ -#define USB_CFG_DEVICE_ID 0xdd, 0x05 /* = 0x05dc = 1500 */ +#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 @@ -249,8 +251,8 @@ section at the end of this file). * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for * details. */ -#define USB_CFG_DEVICE_NAME 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd' -#define USB_CFG_DEVICE_NAME_LEN 8 +#define USB_CFG_DEVICE_NAME 'P', 'S', '/', '2', ' ', 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd', ' ', 'c', 'o', 'n', 'v', 'e', 'r', 't', 'e', 'r' +#define USB_CFG_DEVICE_NAME_LEN 23 /* 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.