Merge branch 'usb_usb_init_fix'
This commit is contained in:
commit
8a8a4cf677
14 changed files with 191 additions and 48 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "tmk_core/protocol/usb_hid/USB_Host_Shield_2.0-git"]
|
||||
path = tmk_core/protocol/usb_hid/USB_Host_Shield_2.0-git
|
||||
url = https://github.com/felis/USB_Host_Shield_2.0.git
|
||||
[submodule "tmk_core/protocol/usb_hid/USB_Host_Shield_2.0-tmk"]
|
||||
path = tmk_core/protocol/usb_hid/USB_Host_Shield_2.0-tmk
|
||||
url = https://github.com/tmk/USB_Host_Shield_2.0.git
|
||||
|
|
|
|||
|
|
@ -1,6 +1,20 @@
|
|||
TARGET = usb_usb_debug
|
||||
UNIMAP_ENABLE = yes
|
||||
|
||||
#UNIMAP_ENABLE = yes
|
||||
#KEYMAP_SECTION_ENABLE = yes
|
||||
#LUFA_DEBUG = yes
|
||||
OPT_DEFS += -DDEBUG_USB_HOST
|
||||
|
||||
# LUFA debug print
|
||||
# This may prevent USB enumeration and keyboard init
|
||||
LUFA_DEBUG = yes
|
||||
# Select one of outputs for debug print
|
||||
LUFA_DEBUG_UART = yes
|
||||
#LUFA_DEBUG_SUART = yes
|
||||
|
||||
# USB_Host_Shield_2.0 debug print
|
||||
# This may prevent USB enumeration and keyboard init
|
||||
#OPT_DEFS += -DDEBUG_USB_HOST
|
||||
|
||||
CONSOLE_ENABLE = yes
|
||||
MOUSEKEY_ENABLE = no
|
||||
EXTRAKEY_ENABLE = no
|
||||
include Makefile
|
||||
|
|
|
|||
|
|
@ -36,4 +36,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
/* key combination for command */
|
||||
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)))
|
||||
|
||||
|
||||
// Disable power saving in USB suspend loop but remote wakeup is still valid.
|
||||
// This allows keep USB::Task() going during suspend without power down time delay.
|
||||
//#define NO_SUSPEND_POWER_DOWN
|
||||
|
||||
|
||||
// Disable USB startup wait, which can delays starting UHS2 Task() for 350-600ms.
|
||||
//#define NO_USB_STARTUP_WAIT_LOOP
|
||||
|
||||
// Disable USB suspend loop, which blocks UHS2 Task() while power saving.
|
||||
// Note that this also disables power saving and remote wakeup from keyboard completely.
|
||||
//#define NO_USB_SUSPEND_LOOP
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "host.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
#include "hook.h"
|
||||
#include "suspend.h"
|
||||
#include "lufa.h"
|
||||
|
||||
|
||||
/* KEY CODE to Matrix
|
||||
*
|
||||
|
|
@ -71,8 +75,6 @@ static bool matrix_is_mod =false;
|
|||
* This supports two cascaded hubs and four keyboards
|
||||
*/
|
||||
USB usb_host;
|
||||
USBHub hub1(&usb_host);
|
||||
USBHub hub2(&usb_host);
|
||||
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> kbd1(&usb_host);
|
||||
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> kbd2(&usb_host);
|
||||
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> kbd3(&usb_host);
|
||||
|
|
@ -81,6 +83,8 @@ KBDReportParser kbd_parser1;
|
|||
KBDReportParser kbd_parser2;
|
||||
KBDReportParser kbd_parser3;
|
||||
KBDReportParser kbd_parser4;
|
||||
USBHub hub1(&usb_host);
|
||||
USBHub hub2(&usb_host);
|
||||
|
||||
|
||||
uint8_t matrix_rows(void) { return MATRIX_ROWS; }
|
||||
|
|
@ -233,3 +237,28 @@ void led_set(uint8_t usb_led)
|
|||
if (kbd3.isReady()) kbd3.SetReport(0, 0, 2, 0, 1, &usb_led);
|
||||
if (kbd4.isReady()) kbd4.SetReport(0, 0, 2, 0, 1, &usb_led);
|
||||
}
|
||||
|
||||
// We need to keep doing UHS2 USB::Task() to initialize keyboard
|
||||
// even before USB is not configured.
|
||||
void hook_usb_startup_wait_loop(void)
|
||||
{
|
||||
matrix_scan();
|
||||
}
|
||||
|
||||
// We need to keep doing UHS2 USB::Task() to initialize keyboard
|
||||
// even during USB bus is suspended and remote wakeup is not enabled yet on LUFA side.
|
||||
// This situation can happen just after pluging converter into USB port.
|
||||
void hook_usb_suspend_loop(void)
|
||||
{
|
||||
#ifndef LUFA_DEBUG_UART
|
||||
// This corrupts debug print when suspend
|
||||
suspend_power_down();
|
||||
#endif
|
||||
if (USB_Device_RemoteWakeupEnabled) {
|
||||
if (suspend_wakeup_condition()) {
|
||||
USB_Device_SendRemoteWakeup();
|
||||
}
|
||||
} else {
|
||||
matrix_scan();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,12 @@ endif
|
|||
ifeq (yes,$(strip $(CONSOLE_ENABLE)))
|
||||
OPT_DEFS += -DCONSOLE_ENABLE
|
||||
else
|
||||
OPT_DEFS += -DNO_PRINT
|
||||
OPT_DEFS += -DNO_DEBUG
|
||||
# Remove print functions when console is disabled and
|
||||
# no other print method like UART is available
|
||||
ifneq (yes, $(strip $(DEBUG_PRINT_AVAILABLE)))
|
||||
OPT_DEFS += -DNO_PRINT
|
||||
OPT_DEFS += -DNO_DEBUG
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (yes,$(strip $(COMMAND_ENABLE)))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// TODO: Teensy support(ATMega32u4/AT90USB128)
|
||||
// Fixed for Arduino Duemilanove ATmega168p by Jun Wako
|
||||
/* UART Example for Teensy USB Development Board
|
||||
* http://www.pjrc.com/teensy/
|
||||
|
|
@ -32,9 +31,42 @@
|
|||
|
||||
#include "uart.h"
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
|
||||
# define UDRn UDR0
|
||||
# define UBRRn UBRR0
|
||||
# define UCSRnA UCSR0A
|
||||
# define UCSRnB UCSR0B
|
||||
# define UCSRnC UCSR0C
|
||||
# define U2Xn U2X0
|
||||
# define RXENn RXEN0
|
||||
# define TXENn TXEN0
|
||||
# define RXCIEn RXCIE0
|
||||
# define UCSZn1 UCSZ01
|
||||
# define UCSZn0 UCSZ00
|
||||
# define UDRIEn UDRIE0
|
||||
# define UDRE_vect USART_UDRE_vect
|
||||
# define RX_vect USART_RX_vect
|
||||
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
|
||||
# define UDRn UDR1
|
||||
# define UBRRn UBRR1
|
||||
# define UCSRnA UCSR1A
|
||||
# define UCSRnB UCSR1B
|
||||
# define UCSRnC UCSR1C
|
||||
# define U2Xn U2X1
|
||||
# define RXENn RXEN1
|
||||
# define TXENn TXEN1
|
||||
# define RXCIEn RXCIE1
|
||||
# define UCSZn1 UCSZ11
|
||||
# define UCSZn0 UCSZ10
|
||||
# define UDRIEn UDRIE1
|
||||
# define UDRE_vect USART1_UDRE_vect
|
||||
# define RX_vect USART1_RX_vect
|
||||
#endif
|
||||
|
||||
|
||||
// These buffers may be any size from 2 to 256 bytes.
|
||||
#define RX_BUFFER_SIZE 64
|
||||
#define TX_BUFFER_SIZE 40
|
||||
#define TX_BUFFER_SIZE 256
|
||||
|
||||
static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];
|
||||
static volatile uint8_t tx_buffer_head;
|
||||
|
|
@ -47,10 +79,10 @@ static volatile uint8_t rx_buffer_tail;
|
|||
void uart_init(uint32_t baud)
|
||||
{
|
||||
cli();
|
||||
UBRR0 = (F_CPU / 4 / baud - 1) / 2;
|
||||
UCSR0A = (1<<U2X0);
|
||||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
|
||||
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
|
||||
UBRRn = (F_CPU / 4 / baud - 1) / 2;
|
||||
UCSRnA = (1<<U2Xn);
|
||||
UCSRnB = (1<<RXENn) | (1<<TXENn) | (1<<RXCIEn);
|
||||
UCSRnC = (1<<UCSZn1) | (1<<UCSZn0);
|
||||
tx_buffer_head = tx_buffer_tail = 0;
|
||||
rx_buffer_head = rx_buffer_tail = 0;
|
||||
sei();
|
||||
|
|
@ -63,11 +95,13 @@ void uart_putchar(uint8_t c)
|
|||
|
||||
i = tx_buffer_head + 1;
|
||||
if (i >= TX_BUFFER_SIZE) i = 0;
|
||||
// return immediately to avoid deadlock when interrupt is disabled(called from ISR)
|
||||
if (tx_buffer_tail == i && (SREG & (1<<SREG_I)) == 0) return;
|
||||
while (tx_buffer_tail == i) ; // wait until space in buffer
|
||||
//cli();
|
||||
tx_buffer[i] = c;
|
||||
tx_buffer_head = i;
|
||||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (1<<UDRIE0);
|
||||
UCSRnB = (1<<RXENn) | (1<<TXENn) | (1<<RXCIEn) | (1<<UDRIEn);
|
||||
//sei();
|
||||
}
|
||||
|
||||
|
|
@ -98,27 +132,27 @@ uint8_t uart_available(void)
|
|||
}
|
||||
|
||||
// Transmit Interrupt
|
||||
ISR(USART_UDRE_vect)
|
||||
ISR(UDRE_vect)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (tx_buffer_head == tx_buffer_tail) {
|
||||
// buffer is empty, disable transmit interrupt
|
||||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
|
||||
UCSRnB = (1<<RXENn) | (1<<TXENn) | (1<<RXCIEn);
|
||||
} else {
|
||||
i = tx_buffer_tail + 1;
|
||||
if (i >= TX_BUFFER_SIZE) i = 0;
|
||||
UDR0 = tx_buffer[i];
|
||||
UDRn = tx_buffer[i];
|
||||
tx_buffer_tail = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Receive Interrupt
|
||||
ISR(USART_RX_vect)
|
||||
ISR(RX_vect)
|
||||
{
|
||||
uint8_t c, i;
|
||||
|
||||
c = UDR0;
|
||||
c = UDRn;
|
||||
i = rx_buffer_head + 1;
|
||||
if (i >= RX_BUFFER_SIZE) i = 0;
|
||||
if (i != rx_buffer_tail) {
|
||||
|
|
@ -21,6 +21,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "keyboard.h"
|
||||
#include "led.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* -------------------------------------
|
||||
* Protocol hooks
|
||||
* ------------------------------------- */
|
||||
|
|
@ -47,6 +51,10 @@ void hook_usb_suspend_loop(void);
|
|||
* the "normal" indicator LED status by default. */
|
||||
void hook_usb_wakeup(void);
|
||||
|
||||
/* Called repeatedly until getting to CONFIGURED state */
|
||||
/* Default behaviour: do nothing. */
|
||||
void hook_usb_startup_wait_loop(void);
|
||||
|
||||
|
||||
/* -------------------------------------
|
||||
* Keyboard hooks
|
||||
|
|
@ -76,5 +84,8 @@ void hook_keyboard_leds_change(uint8_t led_status);
|
|||
/* Default behaviour: do nothing. */
|
||||
void hook_bootmagic(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HOOKS_H_ */
|
||||
|
|
|
|||
|
|
@ -5,9 +5,17 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void suspend_idle(uint8_t timeout);
|
||||
void suspend_power_down(void);
|
||||
bool suspend_wakeup_condition(void);
|
||||
void suspend_wakeup_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ Hook function | Timing
|
|||
`hook_early_init(void)` | Early in the boot process, before the matrix is initialized and before a connection is made with the host. Thus, this hook has access to very few parameters, but it is a good place to define any custom parameters needed by other early processes.
|
||||
`hook_late_init(void)` | Near the end of the boot process, after Boot Magic has run and LEDs have been initialized.
|
||||
`hook_bootmagic(void)` | During the Boot Magic window, after EEPROM and Bootloader checks are made, but before any other built-in Boot Magic checks are made.
|
||||
`hook_usb_startup_wait_loop(void)` | Continuously, until the device gets ready and into USB configured state.
|
||||
|
||||
`hook_usb_wakeup(void)` | When the device wakes up from USB suspend state.
|
||||
`hook_usb_suspend_entry(void)` | When the device enters USB suspend state.
|
||||
`hook_usb_suspend_loop(void)` | Continuously, while the device is in USB suspend state. *Default action:* power down and periodically check the matrix, causing wakeup if needed.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,20 @@ OPT_DEFS += $(LUFA_OPTS)
|
|||
# This indicates using LUFA stack
|
||||
OPT_DEFS += -DPROTOCOL_LUFA
|
||||
|
||||
ifeq (yes,$(strip $(LUFA_DEBUG)))
|
||||
LUFA_OPTS += -DLUFA_DEBUG
|
||||
endif
|
||||
|
||||
ifeq (yes,$(strip $(LUFA_DEBUG_SUART)))
|
||||
SRC += common/avr/suart.S
|
||||
LUFA_OPTS += -DLUFA_DEBUG_SUART
|
||||
# Keep print/debug lines when disabling HID console. See common.mk.
|
||||
DEBUG_PRINT_AVAILABLE = yes
|
||||
endif
|
||||
|
||||
ifeq (yes,$(strip $(LUFA_DEBUG_UART)))
|
||||
SRC += common/avr/uart.c
|
||||
LUFA_OPTS += -DLUFA_DEBUG_UART
|
||||
# Keep print/debug lines when disabling HID console. See common.mk.
|
||||
DEBUG_PRINT_AVAILABLE = yes
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
#include "avr/suart.h"
|
||||
#endif
|
||||
|
||||
#ifdef LUFA_DEBUG_UART
|
||||
#include "uart.h"
|
||||
#endif
|
||||
|
||||
#include "matrix.h"
|
||||
#include "descriptor.h"
|
||||
#include "lufa.h"
|
||||
|
|
@ -218,7 +222,9 @@ static void console_task(void)
|
|||
*/
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
#ifdef LUFA_DEBUG
|
||||
print("[C]");
|
||||
#endif
|
||||
/* For battery powered device */
|
||||
if (!USB_IsInitialized) {
|
||||
USB_Disable();
|
||||
|
|
@ -229,7 +235,9 @@ void EVENT_USB_Device_Connect(void)
|
|||
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
#ifdef LUFA_DEBUG
|
||||
print("[D]");
|
||||
#endif
|
||||
/* For battery powered device */
|
||||
USB_IsInitialized = false;
|
||||
/* TODO: This doesn't work. After several plug in/outs can not be enumerated.
|
||||
|
|
@ -575,25 +583,22 @@ static void send_consumer(uint16_t data)
|
|||
/*******************************************************************************
|
||||
* sendchar
|
||||
******************************************************************************/
|
||||
#ifdef CONSOLE_ENABLE
|
||||
int8_t sendchar(uint8_t c)
|
||||
{
|
||||
#ifdef LUFA_DEBUG_SUART
|
||||
xmit(c);
|
||||
#endif
|
||||
|
||||
bool r = console_putc(c);
|
||||
return (r ? 0 : -1);
|
||||
}
|
||||
#else
|
||||
int8_t sendchar(uint8_t c)
|
||||
{
|
||||
#ifdef LUFA_DEBUG_SUART
|
||||
xmit(c);
|
||||
#ifdef LUFA_DEBUG_UART
|
||||
uart_putchar(c);
|
||||
#endif
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
console_putc(c);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
@ -629,11 +634,15 @@ int main(void)
|
|||
SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
|
||||
#endif
|
||||
|
||||
#ifdef LUFA_DEBUG_UART
|
||||
uart_init(115200);
|
||||
#endif
|
||||
|
||||
// setup sendchar: DO NOT USE print functions before this line
|
||||
print_set_sendchar(sendchar);
|
||||
host_set_driver(&lufa_driver);
|
||||
|
||||
print("Keyboard init.\n");
|
||||
print("\n\nKeyboard init.\n");
|
||||
hook_early_init();
|
||||
keyboard_setup();
|
||||
setup_usb();
|
||||
|
|
@ -645,6 +654,7 @@ int main(void)
|
|||
|
||||
keyboard_init();
|
||||
|
||||
#ifndef NO_USB_STARTUP_WAIT_LOOP
|
||||
/* wait for USB startup */
|
||||
while (USB_DeviceState != DEVICE_STATE_Configured) {
|
||||
#if defined(INTERRUPT_CONTROL_ENDPOINT)
|
||||
|
|
@ -652,19 +662,20 @@ int main(void)
|
|||
#else
|
||||
USB_USBTask();
|
||||
#endif
|
||||
matrix_scan();
|
||||
hook_usb_startup_wait_loop();
|
||||
}
|
||||
print("\nUSB configured.\n");
|
||||
#endif
|
||||
|
||||
hook_late_init();
|
||||
|
||||
print("\nKeyboard start.\n");
|
||||
while (1) {
|
||||
#ifndef NO_USB_SUSPEND_LOOP
|
||||
while (USB_DeviceState == DEVICE_STATE_Suspended) {
|
||||
#ifdef LUFA_DEBUG
|
||||
print("[s]");
|
||||
#endif
|
||||
hook_usb_suspend_loop();
|
||||
}
|
||||
#endif
|
||||
|
||||
keyboard_task();
|
||||
|
||||
|
|
@ -690,12 +701,12 @@ static uint8_t _led_stats = 0;
|
|||
__attribute__((weak))
|
||||
void hook_usb_suspend_entry(void)
|
||||
{
|
||||
// Turn LED off to save power
|
||||
// Set 0 with putting aside status before suspend and restore
|
||||
// it after wakeup, then LED is updated at keyboard_task() in main loop
|
||||
// Turn off LED to save power and keep its status to resotre it later.
|
||||
// LED status will be updated by keyboard_task() in main loop hopefully.
|
||||
_led_stats = keyboard_led_stats;
|
||||
keyboard_led_stats = 0;
|
||||
led_set(keyboard_led_stats);
|
||||
|
||||
// Calling long task here can prevent USB state transition
|
||||
|
||||
matrix_clear();
|
||||
clear_keyboard();
|
||||
|
|
@ -707,7 +718,10 @@ void hook_usb_suspend_entry(void)
|
|||
__attribute__((weak))
|
||||
void hook_usb_suspend_loop(void)
|
||||
{
|
||||
#ifndef LUFA_DEBUG_UART
|
||||
// This corrupts debug print when suspend
|
||||
suspend_power_down();
|
||||
#endif
|
||||
if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
|
||||
USB_Device_SendRemoteWakeup();
|
||||
}
|
||||
|
|
@ -721,10 +735,11 @@ void hook_usb_wakeup(void)
|
|||
sleep_led_disable();
|
||||
#endif
|
||||
|
||||
// Restore LED status
|
||||
// BIOS/grub won't recognize/enumerate if led_set() takes long(around 40ms?)
|
||||
// Converters fall into the case and miss wakeup event(timeout to reply?) in the end.
|
||||
//led_set(host_keyboard_leds());
|
||||
// Instead, restore stats and update at keyboard_task() in main loop
|
||||
// Restore LED status and update at keyboard_task() in main loop
|
||||
keyboard_led_stats = _led_stats;
|
||||
|
||||
// Calling long task here can prevent USB state transition
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void hook_usb_startup_wait_loop(void) {}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ USB_HID_DIR = protocol/usb_hid
|
|||
#
|
||||
# USB Host Shield
|
||||
#
|
||||
USB_HOST_SHIELD_DIR = $(USB_HID_DIR)/USB_Host_Shield_2.0-git
|
||||
USB_HOST_SHIELD_DIR = $(USB_HID_DIR)/USB_Host_Shield_2.0-tmk
|
||||
USB_HOST_SHIELD_SRC = \
|
||||
$(USB_HOST_SHIELD_DIR)/Usb.cpp \
|
||||
$(USB_HOST_SHIELD_DIR)/usbhid.cpp \
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit ed08df7e68af06a5612d938b1bbf55cc4458518a
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 48b2a0950496c7b8ba1bb6ddb937b6f00a6de781
|
||||
Loading…
Add table
Reference in a new issue