Merge branch 'usb_usb_init_fix'

This commit is contained in:
tmk 2019-05-29 15:11:40 +09:00
commit 8a8a4cf677
14 changed files with 191 additions and 48 deletions

6
.gitmodules vendored
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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)))

View file

@ -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) {

View file

@ -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_ */

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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) {}

View file

@ -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