Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Maximilian Friedersdorff 2024-07-04 15:20:50 +01:00
commit caad39421c
170 changed files with 38730 additions and 26170 deletions

View file

@ -104,6 +104,12 @@ void adb_mouse_task(void) {
}
#endif
static bool adb_srq = false;
bool adb_service_request(void)
{
return adb_srq;
}
// This sends Talk command to read data from register and returns length of the data.
uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
{
@ -157,7 +163,8 @@ uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
// portion of the stop bit of any command or data transaction. The device must lengthen
// the stop by a minimum of 140 J.lS beyond its normal duration, as shown in Figure 8-15."
// http://ww1.microchip.com/downloads/en/AppNotes/00591b.pdf
if (!wait_data_hi(500)) { // Service Request(310us Adjustable Keyboard): just ignored
if (!data_in()) { adb_srq = true; } else { adb_srq = false; }
if (!wait_data_hi(500)) { // wait for end of SRQ:(310us Adjustable Keyboard)
xprintf("R");
sei();
return 0;
@ -191,12 +198,14 @@ uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
// |________| |
//
uint8_t lo = (uint8_t) wait_data_hi(130);
if (!lo)
goto error; // no more bit or after stop bit
if (!lo) {
goto error; // SRQ?
}
uint8_t hi = (uint8_t) wait_data_lo(lo);
if (!hi)
goto error; // stop bit extedned by Srq?
if (!hi) {
goto error; // stop bit
}
if (n/8 >= len) continue; // can't store in buf
@ -209,6 +218,7 @@ uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
error:
sei();
_delay_us(200);
return n/8;
}
@ -227,7 +237,8 @@ void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
attention();
send_byte((addr<<4) | ADB_CMD_LISTEN | reg);
place_bit0(); // Stopbit(0)
// TODO: Service Request
if (!data_in()) { adb_srq = true; } else { adb_srq = false; }
wait_data_hi(500); // Service Request
_delay_us(200); // Tlt/Stop to Start
place_bit1(); // Startbit(1)
for (int8_t i = 0; i < len; i++) {
@ -236,6 +247,7 @@ void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
}
place_bit0(); // Stopbit(0);
sei();
_delay_us(200);
}
void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l)
@ -254,13 +266,32 @@ void adb_host_flush(uint8_t addr)
sei();
}
void adb_host_reset(void)
{
cli();
attention();
send_byte(ADB_CMD_RESET);
place_bit0(); // Stopbit(0)
_delay_us(200); // Tlt/Stop to Start
sei();
}
void adb_host_reset_hard(void)
{
data_lo();
_delay_us(3000);
data_hi();
}
// send state of LEDs
void adb_host_kbd_led(uint8_t addr, uint8_t led)
{
// Listen Register2
// upper byte: not used
// lower byte: bit2=ScrollLock, bit1=CapsLock, bit0=NumLock
adb_host_listen(addr, 2, 0, led & 0x07);
uint16_t reg2 = adb_host_talk(addr, 2);
_delay_us(400);
adb_host_listen(addr, 2, reg2 >> 8, (reg2 & 0xF8) | (led & 0x07));
}

View file

@ -68,9 +68,6 @@ POSSIBILITY OF SUCH DAMAGE.
#define ADB_ADDR_13 13
#define ADB_ADDR_14 14
#define ADB_ADDR_15 15
// for temporary purpose, do not use for polling
#define ADB_ADDR_TMP 15
#define ADB_ADDR_MOUSE_POLL 10
// Command Type
#define ADB_CMD_RESET 0
#define ADB_CMD_FLUSH 1
@ -93,6 +90,15 @@ POSSIBILITY OF SUCH DAMAGE.
#define ADB_HANDLER_CLASSIC2_MOUSE 0x02
#define ADB_HANDLER_EXTENDED_MOUSE 0x04
#define ADB_HANDLER_TURBO_MOUSE 0x32
#define ADB_HANDLER_MACALLY2_MOUSE 0x42
#define ADB_HANDLER_MICROSPEED_MACTRAC 0x2F
#define ADB_HANDLER_MICROSPEED_UNKNOWN 0x5F
#define ADB_HANDLER_CONTOUR_MOUSE 0x66
#define ADB_HANDLER_CHPRODUCTS_PRO 0x42
#define ADB_HANDLER_MOUSESYSTEMS_A3 0x03
// pseudo handler
#define ADB_HANDLER_LOGITECH 0x4C
#define ADB_HANDLER_LOGITECH_EXT 0x4D
// ADB host
@ -104,9 +110,13 @@ uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l);
void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len);
void adb_host_flush(uint8_t addr);
void adb_host_reset(void);
void adb_host_reset_hard(void);
void adb_host_kbd_led(uint8_t addr, uint8_t led);
void adb_mouse_task(void);
void adb_mouse_init(void);
uint8_t adb_mouse_buttons(void);
bool adb_service_request(void);
#endif

View file

@ -42,76 +42,75 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdbool.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include "ibmpc.h"
#include "debug.h"
#include "timer.h"
#include "wait.h"
#include "ibmpc.hpp"
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
ibmpc_error = err; \
error = err; \
goto ERROR; \
} \
} while (0)
volatile uint16_t ibmpc_isr_debug = 0;
volatile uint8_t ibmpc_protocol = IBMPC_PROTOCOL_NO;
volatile uint8_t ibmpc_error = IBMPC_ERR_NONE;
IBMPC IBMPC::interface0 = IBMPC(IBMPC_CLOCK_BIT, IBMPC_DATA_BIT);
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1)
IBMPC IBMPC::interface1 = IBMPC(IBMPC_CLOCK_BIT1, IBMPC_DATA_BIT1);
#endif
/* 2-byte buffer for data received from keyboard
* buffer states:
* FFFF: empty
* FFss: one data
* sstt: two data
* eeFF: error
* where ss, tt and ee are 0x00-0xFE. 0xFF means empty or no data in buffer.
*/
static volatile uint16_t recv_data = 0xFFFF;
/* internal state of receiving data */
static volatile uint16_t isr_state = 0x8000;
static uint8_t timer_start = 0;
void ibmpc_host_init(void)
void IBMPC::host_init(void)
{
// initialize reset pin to HiZ
IBMPC_RST_HIZ();
inhibit();
IBMPC_INT_INIT();
IBMPC_INT_OFF();
int_init();
int_off();
host_isr_clear();
}
void ibmpc_host_enable(void)
void IBMPC::host_enable(void)
{
IBMPC_INT_ON();
int_on();
idle();
}
void ibmpc_host_disable(void)
void IBMPC::host_disable(void)
{
IBMPC_INT_OFF();
int_off();
inhibit();
}
int16_t ibmpc_host_send(uint8_t data)
int16_t IBMPC::host_send(uint8_t data)
{
bool parity = true;
ibmpc_error = IBMPC_ERR_NONE;
error = IBMPC_ERR_NONE;
uint8_t retry = 0;
dprintf("w%02X ", data);
IBMPC_INT_OFF();
// Return when receiving data
//if (isr_state & 0x0FFF) {
if (isr_state != 0x8000) {
dprintf("isr:%04X ", isr_state);
return -1;
}
int_off();
RETRY:
/* terminate a transmission if we have */
inhibit();
wait_us(100); // [5]p.54
wait_us(200); // [5]p.54
/* 'Request to Send' and Start bit */
data_lo();
wait_us(100);
wait_us(200);
clock_hi(); // [5]p.54 [clock low]>100us [5]p.50
WAIT(clock_lo, 10000, 1); // [5]p.53, -10ms [5]p.50
WAIT(clock_lo, 15000, 1); // [5]p.54 T13M, -10ms [5]p.50
/* Data bit[2-9] */
for (uint8_t i = 0; i < 8; i++) {
@ -135,117 +134,89 @@ int16_t ibmpc_host_send(uint8_t data)
/* Stop bit */
wait_us(15);
data_hi();
WAIT(clock_hi, 50, 6);
if (ibmpc_protocol == IBMPC_PROTOCOL_AT_Z150) { goto RECV; }
WAIT(clock_lo, 50, 7);
/* Ack */
WAIT(data_lo, 50, 8);
WAIT(data_lo, 300, 6);
WAIT(data_hi, 300, 7);
WAIT(clock_hi, 300, 8);
/* wait for idle state */
WAIT(clock_hi, 50, 9);
WAIT(data_hi, 50, 10);
#ifdef SIEMENS_PCD_SUPPORT
// inhibit - https://github.com/tmk/tmk_keyboard/issues/747
if (protocol & IBMPC_PROTOCOL_AT) {
wait_us(15);
clock_lo();
wait_us(150);
}
#endif
RECV:
// clear buffer to get response correctly
recv_data = 0xFFFF;
ibmpc_host_isr_clear();
host_isr_clear();
idle();
IBMPC_INT_ON();
return ibmpc_host_recv_response();
int_on();
return host_recv_response();
ERROR:
ibmpc_error |= IBMPC_ERR_SEND;
// Retry for Z-150 AT start bit error
if (error == 1 && retry++ < 10) {
error = IBMPC_ERR_NONE;
dprintf("R ");
goto RETRY;
}
isr_debug = isr_state;
error |= IBMPC_ERR_SEND;
inhibit();
wait_ms(2);
idle();
IBMPC_INT_ON();
int_on();
return -1;
}
/*
* Receive data from keyboard
*/
int16_t ibmpc_host_recv(void)
int16_t IBMPC::host_recv(void)
{
uint16_t data = 0;
uint8_t ret = 0xFF;
int16_t ret = -1;
// Enable ISR if buffer was full
if (ringbuf_is_full()) {
host_isr_clear();
int_on();
idle();
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
data = recv_data;
// remove data from buffer:
// FFFF(empty) -> FFFF
// FFss(one data) -> FFFF
// sstt(two data) -> FFtt
// eeFF(errror) -> FFFF
recv_data = data | (((data&0xFF00) == 0xFF00) ? 0x00FF : 0xFF00);
ret = ringbuf_get();
}
if ((data&0x00FF) == 0x00FF) {
// error: eeFF
switch (data>>8) {
case IBMPC_ERR_FF:
// 0xFF(Overrun/Error) from keyboard
dprintf("!FF! ");
ret = 0xFF;
break;
case IBMPC_ERR_FULL:
// buffer full
dprintf("!FULL! ");
ret = 0xFF;
break;
case 0xFF:
// empty: FFFF
return -1;
default:
// other errors
dprintf("e%02X ", data>>8);
return -1;
}
} else {
if ((data | 0x00FF) != 0xFFFF) {
// two data: sstt
dprintf("b:%04X ", data);
ret = (data>>8);
} else {
// one data: FFss
ret = (data&0x00FF);
}
}
//dprintf("i%04X ", ibmpc_isr_debug); ibmpc_isr_debug = 0;
dprintf("r%02X ", ret);
if (ret != -1) dprintf("r%02X ", ret&0xFF);
return ret;
}
int16_t ibmpc_host_recv_response(void)
int16_t IBMPC::host_recv_response(void)
{
// Command may take 25ms/20ms at most([5]p.46, [3]p.21)
uint8_t retry = 25;
int16_t data = -1;
while (retry-- && (data = ibmpc_host_recv()) == -1) {
while (retry-- && (data = host_recv()) == -1) {
wait_ms(1);
}
return data;
}
void ibmpc_host_isr_clear(void)
void IBMPC::host_isr_clear(void)
{
ibmpc_isr_debug = 0;
ibmpc_protocol = 0;
ibmpc_error = 0;
isr_debug = 0;
protocol = 0;
error = 0;
isr_state = 0x8000;
recv_data = 0xFFFF;
ringbuf_reset();
}
#define LO8(w) (*((uint8_t *)&(w)))
#define HI8(w) (*(((uint8_t *)&(w))+1))
// NOTE: With this ISR data line can be read within 2us after clock falling edge.
// To read data line early as possible:
// write naked ISR with asembly code to read the line and call C func to do other job?
ISR(IBMPC_INT_VECT)
void IBMPC::isr(void)
{
uint8_t dbit;
dbit = IBMPC_DATA_PIN&(1<<IBMPC_DATA_BIT);
dbit = IBMPC_DATA_PIN&(1<<data_bit);
// Timeout check
uint8_t t;
@ -256,9 +227,9 @@ ISR(IBMPC_INT_VECT)
timer_start = t;
} else {
// This gives 2.0ms at least before timeout
if ((uint8_t)(t - timer_start) >= 3) {
ibmpc_isr_debug = isr_state;
ibmpc_error = IBMPC_ERR_TIMEOUT;
if ((uint8_t)(t - timer_start) >= 5) {
isr_debug = isr_state;
error = IBMPC_ERR_TIMEOUT;
goto ERROR;
// timeout error recovery - start receiving new data
@ -289,13 +260,12 @@ ISR(IBMPC_INT_VECT)
// x x x x x x x x | *1 0 0 0 0 0 0 0 midway(8 bits received)
// b6 b5 b4 b3 b2 b1 b0 1 | 0 *1 0 0 0 0 0 0 XT_IBM-midway ^1
// b7 b6 b5 b4 b3 b2 b1 b0 | 0 *1 0 0 0 0 0 0 AT-midway ^1
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 *1 0 0 0 0 0 0 XT_Clone-done ^3
// b6 b5 b4 b3 b2 b1 b0 1 | 1 *1 0 0 0 0 0 0 XT_IBM-error ^3
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 *1 0 0 0 0 0 0 XT_Clone-done
// pr b7 b6 b5 b4 b3 b2 b1 | 0 0 *1 0 0 0 0 0 AT-midway[b0=0]
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 0 *1 0 0 0 0 0 XT_IBM-done ^2
// pr b7 b6 b5 b4 b3 b2 b1 | 1 0 *1 0 0 0 0 0 AT-midway[b0=1] ^2
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 1 *1 0 0 0 0 0 XT_IBM-error-done
// x x x x x x x x | x 1 1 0 0 0 0 0 illegal
// x x x x x x x x | 0 1 *1 0 0 0 0 0 illegal
// x x x x x x x x | 1 1 *1 0 0 0 0 0 illegal
// st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0 AT-done
// x x x x x x x x | x x 1 *1 0 0 0 0 illegal
// all other states than above illegal
@ -311,101 +281,120 @@ ISR(IBMPC_INT_VECT)
// midway
goto NEXT;
break;
case 0b11000000: // ^3
{
uint8_t us = 100;
// wait for rising and falling edge of b7 of XT_IBM
while (!(IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT) && us) { wait_us(1); us--; }
if (us) {
// XT_IBM-error: read start(0) as 1
goto NEXT;
} else {
// XT_Clone-done
ibmpc_isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_protocol = IBMPC_PROTOCOL_XT_CLONE;
goto DONE;
}
}
break;
case 0b11100000:
// XT_IBM-error-done
ibmpc_isr_debug = isr_state;
case 0b11000000:
// XT_Clone-done
isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_protocol = IBMPC_PROTOCOL_XT_ERROR;
protocol = IBMPC_PROTOCOL_XT_CLONE;
goto DONE;
break;
case 0b10100000: // ^2
{
uint8_t us = 100;
// wait for rising and falling edge of AT stop bit to discriminate between XT and AT
while (!(IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT) && us) { wait_us(1); us--; }
if (!protocol) {
while (!(IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
while ( (IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
} else if (protocol == IBMPC_PROTOCOL_XT_IBM) {
us = 0;
}
if (us) {
// found stop bit: AT-midway - process the stop bit in next ISR
goto NEXT;
} else {
// no stop bit: XT_IBM-done
ibmpc_isr_debug = isr_state;
isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_protocol = IBMPC_PROTOCOL_XT_IBM;
protocol = IBMPC_PROTOCOL_XT_IBM;
goto DONE;
}
}
}
break;
case 0b00010000:
case 0b10010000:
case 0b01010000:
case 0b11010000:
// AT-done
// TODO: parity check?
ibmpc_isr_debug = isr_state;
isr_debug = isr_state;
// Detect AA with parity error for AT/XT Auto-Switching support
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Keyboard-Converter#atxt-auto-switching
// isr_state: st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0
// 1 '0' 1 0 1 0 1 0 | 1 0 0 *1 0 0 0 0
if (isr_state == 0xAA90) {
error = IBMPC_ERR_PARITY_AA;
goto ERROR;
}
// parit bit check
{
// isr_state: st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0
uint8_t p = (isr_state & 0x4000) ? 1 : 0;
p ^= (isr_state >> 6);
while (p & 0xFE) {
p = (p >> 1) ^ (p & 0x01);
}
if (p == 0) {
error = IBMPC_ERR_PARITY;
goto ERROR;
}
}
// stop bit check
if (isr_state & 0x8000) {
ibmpc_protocol = IBMPC_PROTOCOL_AT;
protocol = IBMPC_PROTOCOL_AT;
} else {
// Zenith Z-150 AT(beige/white lable) asserts stop bit as low
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige
ibmpc_protocol = IBMPC_PROTOCOL_AT_Z150;
protocol = IBMPC_PROTOCOL_AT_Z150;
}
isr_state = isr_state>>6;
goto DONE;
break;
case 0b01100000:
case 0b11100000:
case 0b00110000:
case 0b10110000:
case 0b01110000:
case 0b11110000:
default: // xxxx_oooo(any 1 in low nibble)
// Illegal
ibmpc_isr_debug = isr_state;
ibmpc_error = IBMPC_ERR_ILLEGAL;
protocol = 0;
isr_debug = isr_state;
error = IBMPC_ERR_ILLEGAL;
goto ERROR;
break;
}
ERROR:
// error: eeFF
recv_data = (ibmpc_error<<8) | 0x00FF;
goto CLEAR;
DONE:
if ((isr_state & 0x00FF) == 0x00FF) {
// receive error code 0xFF
ibmpc_error = IBMPC_ERR_FF;
goto ERROR;
}
if (HI8(recv_data) != 0xFF && LO8(recv_data) != 0xFF) {
// buffer full
ibmpc_error = IBMPC_ERR_FULL;
goto ERROR;
#ifdef SIEMENS_PCD_SUPPORT
// inhibit - https://github.com/tmk/tmk_keyboard/issues/747
if (protocol & IBMPC_PROTOCOL_AT) {
clock_lo();
wait_us(150);
clock_hi();
}
#endif
// store data
recv_data = recv_data<<8;
recv_data |= isr_state & 0xFF;
CLEAR:
ringbuf_put(isr_state & 0xFF);
if (ringbuf_is_full()) {
// Disable ISR if buffer is full
int_off();
// inhibit: clock_lo() instead of inhibit() for ISR optimization
clock_lo();
}
if (ringbuf_is_empty()) {
// buffer overflow
error = IBMPC_ERR_FULL;
}
goto END;
ERROR:
// inhibit: Use clock_lo() instead of inhibit() for ISR optimization
clock_lo();
END:
// clear for next data
isr_state = 0x8000;
NEXT:
@ -413,9 +402,25 @@ NEXT:
}
/* send LED state to keyboard */
void ibmpc_host_set_led(uint8_t led)
void IBMPC::host_set_led(uint8_t led)
{
if (0xFA == ibmpc_host_send(0xED)) {
ibmpc_host_send(led);
if (0xFA == host_send(0xED)) {
host_send(led);
}
}
// NOTE: With this ISR data line should be read within 5us after clock falling edge.
// Confirmed that ATmega32u4 can read data line in 2.5us from interrupt after
// ISR prologue pushs r18, r19, r20, r21, r24, r25 r30 and r31 with GCC 5.4.0
ISR(IBMPC_INT_VECT)
{
IBMPC::interface0.isr();
}
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1) && defined(IBMPC_INT_VECT1)
ISR(IBMPC_INT_VECT1)
{
IBMPC::interface1.isr();
}
#endif

View file

@ -1,204 +0,0 @@
/*
Copyright 2010,2011,2012,2013,2019 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 IBMPC_H
#define IBMPC_H
#include <stdbool.h>
#include "wait.h"
#include "print.h"
/*
* IBM PC keyboard protocol
*
* PS/2 Resources
* --------------
* [1] The PS/2 Mouse/Keyboard Protocol
* http://www.computer-engineering.org/ps2protocol/
* Concise and thorough primer of PS/2 protocol.
*
* [2] Keyboard and Auxiliary Device Controller
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Signal Timing and Format
*
* [3] Keyboards(101- and 102-key)
* http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
* Keyboard Layout, Scan Code Set, POR, and Commands.
*
* [4] PS/2 Reference Manuals
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Collection of IBM Personal System/2 documents.
*
* [5] TrackPoint Engineering Specifications for version 3E
* https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
*/
#define IBMPC_ACK 0xFA
#define IBMPC_RESEND 0xFE
#define IBMPC_SET_LED 0xED
#define IBMPC_PROTOCOL_NO 0
#define IBMPC_PROTOCOL_AT 0x10
#define IBMPC_PROTOCOL_AT_Z150 0x11
#define IBMPC_PROTOCOL_XT 0x20
#define IBMPC_PROTOCOL_XT_IBM 0x21
#define IBMPC_PROTOCOL_XT_CLONE 0x22
#define IBMPC_PROTOCOL_XT_ERROR 0x23
// Error numbers
#define IBMPC_ERR_NONE 0
#define IBMPC_ERR_RECV 0x00
#define IBMPC_ERR_SEND 0x10
#define IBMPC_ERR_TIMEOUT 0x20
#define IBMPC_ERR_FULL 0x40
#define IBMPC_ERR_ILLEGAL 0x80
#define IBMPC_ERR_FF 0xF0
#define IBMPC_LED_SCROLL_LOCK 0
#define IBMPC_LED_NUM_LOCK 1
#define IBMPC_LED_CAPS_LOCK 2
extern volatile uint16_t ibmpc_isr_debug;
extern volatile uint8_t ibmpc_protocol;
extern volatile uint8_t ibmpc_error;
void ibmpc_host_init(void);
void ibmpc_host_enable(void);
void ibmpc_host_disable(void);
int16_t ibmpc_host_send(uint8_t data);
int16_t ibmpc_host_recv_response(void);
int16_t ibmpc_host_recv(void);
void ibmpc_host_isr_clear(void);
void ibmpc_host_set_led(uint8_t usb_led);
/*--------------------------------------------------------------------
* static functions
*------------------------------------------------------------------*/
#if defined(__AVR__)
/*
* Clock
*/
static inline void clock_lo(void)
{
IBMPC_CLOCK_PORT &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_DDR |= (1<<IBMPC_CLOCK_BIT);
}
static inline void clock_hi(void)
{
/* input with pull up */
IBMPC_CLOCK_DDR &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_PORT |= (1<<IBMPC_CLOCK_BIT);
}
static inline bool clock_in(void)
{
IBMPC_CLOCK_DDR &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_PORT |= (1<<IBMPC_CLOCK_BIT);
wait_us(1);
return IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT);
}
/*
* Data
*/
static inline void data_lo(void)
{
IBMPC_DATA_PORT &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_DDR |= (1<<IBMPC_DATA_BIT);
}
static inline void data_hi(void)
{
/* input with pull up */
IBMPC_DATA_DDR &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_PORT |= (1<<IBMPC_DATA_BIT);
}
static inline bool data_in(void)
{
IBMPC_DATA_DDR &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_PORT |= (1<<IBMPC_DATA_BIT);
wait_us(1);
return IBMPC_DATA_PIN&(1<<IBMPC_DATA_BIT);
}
#endif
static inline uint16_t wait_clock_lo(uint16_t us)
{
while (clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static inline uint16_t wait_clock_hi(uint16_t us)
{
while (!clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static inline uint16_t wait_data_lo(uint16_t us)
{
while (data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static inline uint16_t wait_data_hi(uint16_t us)
{
while (!data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
/* idle state that device can send */
static inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send(AT), soft reset(XT) */
static inline void inhibit(void)
{
clock_lo();
data_hi();
}
/* inhibit device to send(XT) */
static inline void inhibit_xt(void)
{
clock_hi();
data_lo();
}
#endif

275
tmk_core/protocol/ibmpc.hpp Normal file
View file

@ -0,0 +1,275 @@
/*
Copyright 2010,2011,2012,2013,2019 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 IBMPC_HPP
#define IBMPC_HPP
#include <stdbool.h>
#include "wait.h"
/*
* IBM PC keyboard protocol
*
* PS/2 Resources
* --------------
* [1] The PS/2 Mouse/Keyboard Protocol
* http://www.computer-engineering.org/ps2protocol/
* Concise and thorough primer of PS/2 protocol.
*
* [2] Keyboard and Auxiliary Device Controller
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Signal Timing and Format
*
* [3] Keyboards(101- and 102-key)
* http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
* Keyboard Layout, Scan Code Set, POR, and Commands.
*
* [4] PS/2 Reference Manuals
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Collection of IBM Personal System/2 documents.
*
* [5] TrackPoint Engineering Specifications for version 3E
* https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
*/
#define IBMPC_ACK 0xFA
#define IBMPC_RESEND 0xFE
#define IBMPC_SET_LED 0xED
#define IBMPC_PROTOCOL_NO 0
#define IBMPC_PROTOCOL_AT 0x10
#define IBMPC_PROTOCOL_AT_Z150 0x11
#define IBMPC_PROTOCOL_XT 0x20
#define IBMPC_PROTOCOL_XT_IBM 0x21
#define IBMPC_PROTOCOL_XT_CLONE 0x22
// Error numbers
#define IBMPC_ERR_NONE 0
#define IBMPC_ERR_PARITY 0x01
#define IBMPC_ERR_PARITY_AA 0x02
#define IBMPC_ERR_SEND 0x10
#define IBMPC_ERR_TIMEOUT 0x20
#define IBMPC_ERR_FULL 0x40
#define IBMPC_ERR_ILLEGAL 0x80
#define IBMPC_LED_SCROLL_LOCK 0
#define IBMPC_LED_NUM_LOCK 1
#define IBMPC_LED_CAPS_LOCK 2
class IBMPC
{
public:
static IBMPC interface0;
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1)
static IBMPC interface1;
#endif
volatile uint16_t isr_debug;
volatile uint8_t protocol;
volatile uint8_t error;
void host_init(void);
void host_enable(void);
void host_disable(void);
int16_t host_send(uint8_t data);
int16_t host_recv_response(void);
int16_t host_recv(void);
void host_isr_clear(void);
void host_set_led(uint8_t led);
IBMPC(uint8_t clock, uint8_t data) :
isr_debug(IBMPC_ERR_NONE), protocol(IBMPC_PROTOCOL_NO), error(IBMPC_ERR_NONE),
isr_state(0x8000), timer_start(0), clock_bit(clock), data_bit(data),
clock_mask(1 << clock), data_mask(1 << data) {
};
void isr(void);
private:
volatile uint16_t isr_state;
uint8_t timer_start;
/* ring buffer */
// Size should be power of 2
#define RINGBUF_SIZE 16
uint8_t rb_head;
uint8_t rb_tail;
uint8_t rb_buffer[RINGBUF_SIZE];
const uint8_t clock_bit, data_bit;
const uint8_t clock_mask, data_mask;
inline void clock_lo(void) __attribute__((__always_inline__)) // needed for ISR optimization
{
IBMPC_CLOCK_PORT &= ~clock_mask;
IBMPC_CLOCK_DDR |= clock_mask;
}
inline void clock_hi(void)
{
/* input with pull up */
IBMPC_CLOCK_DDR &= ~clock_mask;
IBMPC_CLOCK_PORT |= clock_mask;
}
inline bool clock_in(void)
{
IBMPC_CLOCK_DDR &= ~clock_mask;
IBMPC_CLOCK_PORT |= clock_mask;
wait_us(1);
return IBMPC_CLOCK_PIN & clock_mask;
}
inline void data_lo(void)
{
IBMPC_DATA_PORT &= ~data_mask;
IBMPC_DATA_DDR |= data_mask;
}
inline void data_hi(void)
{
/* input with pull up */
IBMPC_DATA_DDR &= ~data_mask;
IBMPC_DATA_PORT |= data_mask;
}
inline bool data_in(void)
{
IBMPC_DATA_DDR &= ~data_mask;
IBMPC_DATA_PORT |= data_mask;
wait_us(1);
return IBMPC_DATA_PIN & data_mask;
}
inline uint16_t wait_clock_lo(uint16_t us)
{
while (clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_clock_hi(uint16_t us)
{
while (!clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_data_lo(uint16_t us)
{
while (data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_data_hi(uint16_t us)
{
while (!data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
/* idle state that device can send */
inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send(AT), soft reset(XT) */
inline void inhibit(void)
{
clock_lo();
data_hi();
}
/* inhibit device to send(XT) */
inline void inhibit_xt(void)
{
clock_hi();
data_lo();
}
void int_init(void)
{
// interrupt at falling edge
if (clock_bit < 4) {
EICRA |= (0x2 << ((clock_bit&0x3)*2));
} else {
EICRB |= (0x2 << ((clock_bit&0x3)*2));
}
}
void int_on(void)
{
EIFR |= clock_mask;
EIMSK |= clock_mask;
}
inline void int_off(void) __attribute__((__always_inline__)) // needed for ISR optimization
{
EIMSK &= ~clock_mask;
}
/*
* ring buffer
*/
inline int16_t ringbuf_get(void) __attribute__((__always_inline__))
{
if (ringbuf_is_empty()) return -1;
uint8_t data = rb_buffer[rb_tail];
rb_tail++;
rb_tail &= (RINGBUF_SIZE - 1);
return data;
}
inline void ringbuf_put(uint8_t data) __attribute__((__always_inline__))
{
rb_buffer[rb_head] = data;
rb_head++;
rb_head &= (RINGBUF_SIZE - 1);
}
inline bool ringbuf_is_empty(void) __attribute__((__always_inline__))
{
return (rb_head == rb_tail);
}
inline bool ringbuf_is_full(void) __attribute__((__always_inline__))
{
return (((rb_head + 1) & (RINGBUF_SIZE - 1)) == rb_tail);
}
inline void ringbuf_reset(void) __attribute__((__always_inline__))
{
rb_head = 0;
rb_tail = 0;
}
};
#endif

View file

@ -4,6 +4,10 @@ TMK_LUFA_DIR = protocol/lufa
TMK_LUFA_PATH ?= $(TMK_LUFA_DIR)/lufa-abcminiuser
# Version string
TMK_LUFA_VERSION := $(shell (cd $(TMK_DIR)/$(TMK_LUFA_PATH); git rev-parse --short=6 HEAD || echo 'unknown') 2> /dev/null)
OPT_DEFS += -DTMK_LUFA_VERSION=$(TMK_LUFA_VERSION)
# Create the LUFA source path variables by including the LUFA makefile
ifneq (, $(wildcard $(TMK_DIR)/$(TMK_LUFA_PATH)/LUFA/Build/LUFA/lufa-sources.mk))
LUFA_PATH = $(TMK_LUFA_PATH)/LUFA
@ -47,7 +51,7 @@ TMK_LUFA_OPTS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_E
TMK_LUFA_OPTS += -DFIXED_CONTROL_ENDPOINT_SIZE=8
TMK_LUFA_OPTS += -DFIXED_NUM_CONFIGURATIONS=1
# Remote wakeup fix for ATmega32U2 https://github.com/tmk/tmk_keyboard/issues/361
ifeq ($(MCU),atmega32u2)
ifeq (atmega32u2,$(strip $(MCU)))
TMK_LUFA_OPTS += -DNO_LIMITED_CONTROLLER_CONNECT
endif

View file

@ -44,8 +44,11 @@
/*******************************************************************************
* HID Report Descriptors
******************************************************************************/
#ifndef NO_KEYBOARD
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
{
#ifndef NKRO_ENABLE
/* 6KRO - Boot protocol */
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x06), /* Keyboard */
HID_RI_COLLECTION(8, 0x01), /* Application */
@ -81,29 +84,65 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
};
#else
/* NKRO - Report protocol */
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x06), /* Keyboard */
HID_RI_COLLECTION(8, 0x01), /* Application */
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
#ifdef MOUSE_ENABLE
HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
#endif
};
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
{
#ifdef MOUSE_ENABLE
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x02), /* Mouse */
HID_RI_COLLECTION(8, 0x01), /* Application */
HID_RI_USAGE(8, 0x01), /* Pointer */
HID_RI_COLLECTION(8, 0x00), /* Physical */
HID_RI_REPORT_ID(8, REPORT_ID_MOUSE),
HID_RI_USAGE_PAGE(8, 0x09), /* Button */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Button 1 */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Button 5 */
HID_RI_USAGE_MAXIMUM(8, 0x08), /* Button 8 */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_INPUT(8, HID_IOF_CONSTANT),
#ifndef MOUSE_EXT_REPORT
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x30), /* Usage X */
HID_RI_USAGE(8, 0x31), /* Usage Y */
@ -112,6 +151,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
#else
/* Boot protocol XY ignored in Report protocol */
HID_RI_USAGE_PAGE(8, 0xff), /* Vendor */
HID_RI_USAGE(8, 0xff), /* Vendor */
HID_RI_LOGICAL_MINIMUM(8, -127),
HID_RI_LOGICAL_MAXIMUM(8, 127),
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x30), /* Usage X */
HID_RI_USAGE(8, 0x31), /* Usage Y */
HID_RI_LOGICAL_MINIMUM(16, -32767),
HID_RI_LOGICAL_MAXIMUM(16, 32767),
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 16),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
#endif
HID_RI_USAGE(8, 0x38), /* Wheel */
HID_RI_LOGICAL_MINIMUM(8, -127),
@ -130,12 +188,9 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
HID_RI_END_COLLECTION(0),
HID_RI_END_COLLECTION(0),
};
#endif
#ifdef EXTRAKEY_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x80), /* System Control */
HID_RI_COLLECTION(8, 0x01), /* Application */
@ -161,6 +216,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
HID_RI_REPORT_COUNT(8, 1),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
#endif
};
#endif
@ -186,7 +242,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] =
};
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
@ -272,6 +328,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
/*
* Keyboard
*/
#ifndef NO_KEYBOARD
.Keyboard_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -305,14 +362,20 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | KEYBOARD_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
#ifdef NKRO_ENABLE
.EndpointSize = NKRO_EPSIZE,
.PollingIntervalMS = 0x01
#else
.EndpointSize = KEYBOARD_EPSIZE,
.PollingIntervalMS = 0x0A
#endif
},
#endif
/*
* Mouse
*/
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
.Mouse_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -323,8 +386,13 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
#if defined(MOUSE_ENABLE)
.SubClass = HID_CSCP_BootSubclass,
.Protocol = HID_CSCP_MouseBootProtocol,
#else
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
#endif
.InterfaceStrIndex = NO_DESCRIPTOR
},
@ -347,49 +415,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | MOUSE_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MOUSE_EPSIZE,
.PollingIntervalMS = 0x0A
},
#endif
/*
* Extra
*/
#ifdef EXTRAKEY_ENABLE
.Extrakey_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = EXTRAKEY_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.Extrakey_HID =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
.HIDReportLength = sizeof(ExtrakeyReport)
},
.Extrakey_INEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DIR_IN | EXTRAKEY_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = EXTRAKEY_EPSIZE,
.PollingIntervalMS = 0x0A
.PollingIntervalMS = 0x01
},
#endif
@ -404,7 +430,8 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.InterfaceNumber = CONSOLE_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 2,
//.TotalEndpoints = 2,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
@ -434,6 +461,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.PollingIntervalMS = 0x01
},
/*
.Console_OUTEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
@ -443,12 +471,13 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointSize = CONSOLE_EPSIZE,
.PollingIntervalMS = 0x01
},
*/
#endif
/*
* NKRO
*/
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
.NKRO_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -561,29 +590,25 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
break;
case HID_DTYPE_HID:
switch (wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
Address = &ConfigurationDescriptor.Keyboard_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#ifdef MOUSE_ENABLE
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
case MOUSE_INTERFACE:
Address = &ConfigurationDescriptor.Mouse_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef EXTRAKEY_ENABLE
case EXTRAKEY_INTERFACE:
Address = &ConfigurationDescriptor.Extrakey_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConfigurationDescriptor.Console_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
case NKRO_INTERFACE:
Address = &ConfigurationDescriptor.NKRO_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
@ -593,29 +618,25 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
break;
case HID_DTYPE_Report:
switch (wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
Address = &KeyboardReport;
Size = sizeof(KeyboardReport);
break;
#ifdef MOUSE_ENABLE
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
case MOUSE_INTERFACE:
Address = &MouseReport;
Size = sizeof(MouseReport);
break;
#endif
#ifdef EXTRAKEY_ENABLE
case EXTRAKEY_INTERFACE:
Address = &ExtrakeyReport;
Size = sizeof(ExtrakeyReport);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConsoleReport;
Size = sizeof(ConsoleReport);
break;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
case NKRO_INTERFACE:
Address = &NKROReport;
Size = sizeof(NKROReport);

View file

@ -52,34 +52,29 @@ typedef struct
{
USB_Descriptor_Configuration_Header_t Config;
#ifndef NO_KEYBOARD
// Keyboard HID Interface
USB_Descriptor_Interface_t Keyboard_Interface;
USB_HID_Descriptor_HID_t Keyboard_HID;
USB_Descriptor_Endpoint_t Keyboard_INEndpoint;
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
// Mouse HID Interface
USB_Descriptor_Interface_t Mouse_Interface;
USB_HID_Descriptor_HID_t Mouse_HID;
USB_Descriptor_Endpoint_t Mouse_INEndpoint;
#endif
#ifdef EXTRAKEY_ENABLE
// Extrakey HID Interface
USB_Descriptor_Interface_t Extrakey_Interface;
USB_HID_Descriptor_HID_t Extrakey_HID;
USB_Descriptor_Endpoint_t Extrakey_INEndpoint;
#endif
#ifdef CONSOLE_ENABLE
// Console HID Interface
USB_Descriptor_Interface_t Console_Interface;
USB_HID_Descriptor_HID_t Console_HID;
USB_Descriptor_Endpoint_t Console_INEndpoint;
USB_Descriptor_Endpoint_t Console_OUTEndpoint;
// USB_Descriptor_Endpoint_t Console_OUTEndpoint;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
// NKRO HID Interface
USB_Descriptor_Interface_t NKRO_Interface;
USB_HID_Descriptor_HID_t NKRO_HID;
@ -89,27 +84,25 @@ typedef struct
/* index of interface */
#define KEYBOARD_INTERFACE 0
#ifndef NO_KEYBOARD
# define KEYBOARD_INTERFACE 0
#else
# define KEYBOARD_INTERFACE -1
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
# define MOUSE_INTERFACE (KEYBOARD_INTERFACE + 1)
#else
# define MOUSE_INTERFACE KEYBOARD_INTERFACE
#endif
#ifdef EXTRAKEY_ENABLE
# define EXTRAKEY_INTERFACE (MOUSE_INTERFACE + 1)
#else
# define EXTRAKEY_INTERFACE MOUSE_INTERFACE
#endif
#ifdef CONSOLE_ENABLE
# define CONSOLE_INTERFACE (EXTRAKEY_INTERFACE + 1)
# define CONSOLE_INTERFACE (MOUSE_INTERFACE + 1)
#else
# define CONSOLE_INTERFACE EXTRAKEY_INTERFACE
# define CONSOLE_INTERFACE MOUSE_INTERFACE
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
# define NKRO_INTERFACE (CONSOLE_INTERFACE + 1)
#else
# define NKRO_INTERFACE CONSOLE_INTERFACE
@ -121,28 +114,32 @@ typedef struct
// Endopoint number and size
#define KEYBOARD_IN_EPNUM 1
#ifndef NO_KEYBOARD
# define KEYBOARD_IN_EPNUM 1
#else
# define KEYBOARD_IN_EPNUM 0
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
# define MOUSE_IN_EPNUM (KEYBOARD_IN_EPNUM + 1)
#else
# define MOUSE_IN_EPNUM KEYBOARD_IN_EPNUM
#endif
#ifdef EXTRAKEY_ENABLE
# define EXTRAKEY_IN_EPNUM (MOUSE_IN_EPNUM + 1)
#else
# define EXTRAKEY_IN_EPNUM MOUSE_IN_EPNUM
#endif
#ifdef CONSOLE_ENABLE
# define CONSOLE_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 1)
// ATMega32U2 doesn't support double bank on endpoint 1 and 2, use 3 or 4
# if MOUSE_IN_EPNUM < 2
# define CONSOLE_IN_EPNUM 3
# define CONSOLE_OUT_EPNUM 3
# else
# define CONSOLE_IN_EPNUM (MOUSE_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (MOUSE_IN_EPNUM + 1)
# endif
#else
# define CONSOLE_OUT_EPNUM EXTRAKEY_IN_EPNUM
# define CONSOLE_OUT_EPNUM MOUSE_IN_EPNUM
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
# define NKRO_IN_EPNUM (CONSOLE_OUT_EPNUM + 1)
#else
# define NKRO_IN_EPNUM CONSOLE_OUT_EPNUM
@ -150,13 +147,18 @@ typedef struct
/* Check number of endpoints. ATmega32u2 has only four except for control endpoint. */
#if defined(__AVR_ATmega32U2__) && NKRO_IN_EPNUM > 4
# error "Endpoints are not available enough to support all functions. Disable some of build options in Makefile.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO)"
# error "Endpoints are not available enough to support all functions. Disable some of build options in Makefile.(MOUSEKEY, CONSOLE, NKRO)"
#endif
#define KEYBOARD_EPSIZE 8
#if defined(MOUSE_EXT_REPORT)
#define MOUSE_EPSIZE 10
#else
#define MOUSE_EPSIZE 8
#define EXTRAKEY_EPSIZE 8
#endif
#define CONSOLE_EPSIZE 32
#define NKRO_EPSIZE 32

View file

@ -41,6 +41,7 @@
#include "host_driver.h"
#include "keyboard.h"
#include "action.h"
#include "action_util.h"
#include "led.h"
#include "sendchar.h"
#include "ringbuf.h"
@ -68,26 +69,35 @@
//#define TMK_LUFA_DEBUG
#ifndef NO_KEYBOARD
uint8_t keyboard_idle = 0;
/* 0: Boot Protocol, 1: Report Protocol(default) */
uint8_t keyboard_protocol = 1;
static uint8_t keyboard_led_stats = 0;
static report_keyboard_t keyboard_report_sent = (report_keyboard_t){};
#endif
static report_keyboard_t keyboard_report_sent;
#ifdef MOUSE_ENABLE
uint8_t mouse_protocol = 1;
#endif
/* Host driver */
#ifndef NO_KEYBOARD
static uint8_t keyboard_leds(void);
static void send_keyboard(report_keyboard_t *report);
#endif
static void send_mouse(report_mouse_t *report);
static void send_system(uint16_t data);
static void send_consumer(uint16_t data);
host_driver_t lufa_driver = {
keyboard_leds,
send_keyboard,
send_mouse,
send_system,
send_consumer
#ifndef NO_KEYBOARD
.keyboard_leds = keyboard_leds,
.send_keyboard = send_keyboard,
#endif
.send_mouse = send_mouse,
.send_system = send_system,
.send_consumer = send_consumer
};
@ -95,7 +105,11 @@ host_driver_t lufa_driver = {
* Console
******************************************************************************/
#ifdef CONSOLE_ENABLE
#define SENDBUF_SIZE 256
# ifdef _AVR_ATmega32U2_H_
# define SENDBUF_SIZE 128
# else
# define SENDBUF_SIZE 256
# endif
static uint8_t sbuf[SENDBUF_SIZE];
static ringbuf_t sendbuf = {
.buffer = sbuf,
@ -296,6 +310,19 @@ void EVENT_USB_Device_Reset(void)
#ifdef TMK_LUFA_DEBUG
print("[R]");
#endif
// reset to initial state: protocol to Report(default)
#ifndef NO_KEYBOARD
keyboard_protocol = 1;
keyboard_idle = 0;
keyboard_led_stats = 0;
keyboard_report_sent = (report_keyboard_t){};
// keyboard_report keys/bits part is not compatible between Boot and Report protocol
clear_keys();
#endif
#ifdef MOUSE_ENABLE
mouse_protocol = 1;
#endif
}
void EVENT_USB_Device_Suspend()
@ -327,33 +354,35 @@ void EVENT_USB_Device_ConfigurationChanged(void)
#endif
bool ConfigSuccess = true;
#ifndef NO_KEYBOARD
/* Setup Keyboard HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
#ifdef NKRO_ENABLE
NKRO_EPSIZE,
#else
KEYBOARD_EPSIZE,
#endif
ENDPOINT_BANK_SINGLE);
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
/* Setup Mouse HID Report Endpoint */
ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#ifdef EXTRAKEY_ENABLE
/* Setup Extra HID Report Endpoint */
ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#ifdef CONSOLE_ENABLE
// ATMega32U2 doesn't support double bank on endpoint 1 and 2, use 3 or 4
/* Setup Console HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
#if 0
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#endif
#ifdef NKRO_ENABLE
#ifdef NKRO_6KRO_ENABLE
/* Setup NKRO HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
@ -378,15 +407,16 @@ Other Device Required Optional Optional Optional Optional Opti
*/
void EVENT_USB_Device_ControlRequest(void)
{
uint8_t* ReportData = NULL;
uint8_t ReportSize = 0;
/* Handle HID Class specific requests */
switch (USB_ControlRequest.bRequest)
{
case HID_REQ_GetReport:
#ifndef NO_KEYBOARD
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
uint8_t* ReportData = NULL;
uint8_t ReportSize = 0;
Endpoint_ClearSETUP();
// Interface
@ -405,6 +435,7 @@ void EVENT_USB_Device_ControlRequest(void)
xprintf("[r%d]", USB_ControlRequest.wIndex);
#endif
}
#endif
break;
case HID_REQ_SetReport:
@ -413,8 +444,9 @@ void EVENT_USB_Device_ControlRequest(void)
// Interface
switch (USB_ControlRequest.wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
#ifdef NKRO_ENABLE
#ifdef NKRO_6KRO_ENABLE
case NKRO_INTERFACE:
#endif
Endpoint_ClearSETUP();
@ -428,9 +460,10 @@ void EVENT_USB_Device_ControlRequest(void)
Endpoint_ClearOUT();
Endpoint_ClearStatusStage();
#ifdef TMK_LUFA_DEBUG
xprintf("[L%d]", USB_ControlRequest.wIndex);
xprintf("[L%d %02X]", USB_ControlRequest.wIndex, keyboard_led_stats);
#endif
break;
#endif
}
}
@ -440,6 +473,7 @@ void EVENT_USB_Device_ControlRequest(void)
case HID_REQ_GetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
@ -450,34 +484,58 @@ void EVENT_USB_Device_ControlRequest(void)
print("[p]");
#endif
}
#endif
#if defined(MOUSE_ENABLE)
if (USB_ControlRequest.wIndex == MOUSE_INTERFACE) {
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(mouse_protocol);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
}
#endif
}
break;
case HID_REQ_SetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
clear_keyboard();
#ifdef TMK_LUFA_DEBUG
print("[P]");
xprintf("[P%d %04X]", USB_ControlRequest.wIndex, USB_ControlRequest.wValue);
#endif
}
#endif
#if defined(MOUSE_ENABLE)
if (USB_ControlRequest.wIndex == MOUSE_INTERFACE) {
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
mouse_protocol = (USB_ControlRequest.wValue & 0xFF);
#ifdef TMK_LUFA_DEBUG
xprintf("[P%d %04X]", USB_ControlRequest.wIndex, USB_ControlRequest.wValue);
#endif
}
#endif
}
break;
case HID_REQ_SetIdle:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
#ifdef TMK_LUFA_DEBUG
xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
xprintf("[I%d %04X]", USB_ControlRequest.wIndex, USB_ControlRequest.wValue);
#endif
#endif
}
@ -485,6 +543,7 @@ void EVENT_USB_Device_ControlRequest(void)
case HID_REQ_GetIdle:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(keyboard_idle);
@ -492,6 +551,7 @@ void EVENT_USB_Device_ControlRequest(void)
Endpoint_ClearStatusStage();
#ifdef TMK_LUFA_DEBUG
print("[i]");
#endif
#endif
}
@ -502,6 +562,7 @@ void EVENT_USB_Device_ControlRequest(void)
/*******************************************************************************
* Host driver
******************************************************************************/
#ifndef NO_KEYBOARD
static uint8_t keyboard_leds(void)
{
return keyboard_led_stats;
@ -515,10 +576,14 @@ static void send_keyboard(report_keyboard_t *report)
return;
/* Select the Keyboard Report Endpoint */
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
if (keyboard_protocol && keyboard_nkro) {
/* Report protocol - NKRO */
#if defined(NKRO_6KRO_ENABLE)
Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
#else
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
#endif
/* Check if write ready for a polling interval around 1ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
@ -546,6 +611,7 @@ static void send_keyboard(report_keyboard_t *report)
keyboard_report_sent = *report;
}
#endif
static void send_mouse(report_mouse_t *report)
{
@ -563,7 +629,14 @@ static void send_mouse(report_mouse_t *report)
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Mouse Report Data */
Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
if (mouse_protocol) {
// Report
Endpoint_Write_8(REPORT_ID_MOUSE);
Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
} else {
// Boot
Endpoint_Write_Stream_LE(report, 3, NULL);
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
@ -578,11 +651,19 @@ static void send_system(uint16_t data)
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
report_extra_t r = {
.report_id = REPORT_ID_SYSTEM,
.usage = data - SYSTEM_POWER_DOWN + 1
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
#ifdef MOUSE_ENABLE
// Not send while mouse is set to Boot Protocol
if (mouse_protocol == 0)
return;
#endif
report_extra_t r = { .report_id = REPORT_ID_SYSTEM };
if (data < SYSTEM_POWER_DOWN) {
r.usage = 0;
} else {
r.usage = data - SYSTEM_POWER_DOWN + 1;
}
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@ -601,11 +682,17 @@ static void send_consumer(uint16_t data)
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
#ifdef MOUSE_ENABLE
// Not send while mouse is set to Boot Protocol
if (mouse_protocol == 0)
return;
#endif
report_extra_t r = {
.report_id = REPORT_ID_CONSUMER,
.usage = data
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@ -677,21 +764,40 @@ int main(void)
print_set_sendchar(sendchar);
host_set_driver(&lufa_driver);
print("\n\nTMK:" STR(TMK_VERSION) "/LUFA\n\n");
print("\nTMK:" STR(TMK_VERSION) "/LUFA:" STR(TMK_LUFA_VERSION)
#ifdef TMK_USB_HOST_SHIELD_VERSION
"/UHS2:" STR(TMK_USB_HOST_SHIELD_VERSION)
#endif
"\n");
hook_early_init();
#ifndef NO_KEYBOARD
keyboard_setup();
#endif
setup_usb();
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
sei();
#ifndef NO_KEYBOARD
keyboard_init();
#else
// TODO: keyboard_init() should be used only for things related to keyboard
timer_init();
#endif
#ifndef NO_USB_STARTUP_WAIT_LOOP
/* wait for USB startup */
while (USB_DeviceState != DEVICE_STATE_Configured) {
while (USB_DeviceState != DEVICE_STATE_Configured
#ifdef CONSOLE_ENABLE
|| !console_is_ready()
#endif
) {
#if defined(INTERRUPT_CONTROL_ENDPOINT)
;
#else
@ -704,7 +810,7 @@ int main(void)
hook_late_init();
print("\nKeyboard start.\n");
print("\nLoop start.\n");
while (1) {
#ifndef NO_USB_SUSPEND_LOOP
while (USB_DeviceState == DEVICE_STATE_Suspended) {
@ -712,7 +818,11 @@ int main(void)
}
#endif
hook_main_loop();
#ifndef NO_KEYBOARD
keyboard_task();
#endif
#ifdef CONSOLE_ENABLE
console_task();
@ -732,10 +842,13 @@ void hook_early_init(void) {}
__attribute__((weak))
void hook_late_init(void) {}
#ifndef NO_KEYBOARD
static uint8_t _led_stats = 0;
#endif
__attribute__((weak))
void hook_usb_suspend_entry(void)
{
#ifndef NO_KEYBOARD
// 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;
@ -745,6 +858,7 @@ void hook_usb_suspend_entry(void)
matrix_clear();
clear_keyboard();
#endif
#ifdef SLEEP_LED_ENABLE
sleep_led_enable();
#endif
@ -770,8 +884,10 @@ void hook_usb_wakeup(void)
sleep_led_disable();
#endif
#ifndef NO_KEYBOARD
// Restore LED status and update at keyboard_task() in main loop
keyboard_led_stats = _led_stats;
#endif
// Calling long task here can prevent USB state transition
}

View file

@ -494,10 +494,19 @@ RAW CODE:
* 0x71, 0x79,DD / 0xF1, 0x79, 0xUU
MODEL NUMBER:
M0110: 0x09 00001001 : model number 4 (100)
M0110A: 0x0B 00001011 : model number 5 (101)
M0110 & M0120: ???
MODEL CODE:
Model Code Layout Made in Desc
---------------------------------------------------------------------
M0110(GS536) 0x03 US USA
M0110(GS624) 0x09 US USA
M0110F 0x03 French Ireland https://github.com/tmk/tmk_keyboard/issues/771
M0110A(M923) 0x0B US
M0110AJ(M839) 0x0B US
M0110AJ(A615) 0x0B US
M0120(BCG9GRM0120) 0x11
M0120 & M0110(G536) 0x13
M0120 & M0110(G624) 0x19
M0120 & M0110A(M923) 0x1B
Scan Code
@ -572,8 +581,8 @@ Scan Code
References
----------
Technical Info for 128K/512K and Plus
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20128K.pdf
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20Plus.pdf
https://www.apple.asimov.net/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20128K.pdf
https://www.apple.asimov.net/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20Plus.pdf
Protocol:
Page 20 of Tech Info for 128K/512K
http://www.mac.linux-m68k.org/devel/plushw.php

View file

@ -1,168 +0,0 @@
/*
Copyright 2012 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 "news.h"
void news_init(void)
{
NEWS_KBD_RX_INIT();
}
// RX ring buffer
#define RBUF_SIZE 8
static uint8_t rbuf[RBUF_SIZE];
static uint8_t rbuf_head = 0;
static uint8_t rbuf_tail = 0;
uint8_t news_recv(void)
{
uint8_t data = 0;
if (rbuf_head == rbuf_tail) {
return 0;
}
data = rbuf[rbuf_tail];
rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE;
return data;
}
// USART RX complete interrupt
ISR(NEWS_KBD_RX_VECT)
{
uint8_t next = (rbuf_head + 1) % RBUF_SIZE;
if (next != rbuf_tail) {
rbuf[rbuf_head] = NEWS_KBD_RX_DATA;
rbuf_head = next;
}
}
/*
SONY NEWS Keyboard Protocol
===========================
Resources
---------
Mouse protocol of NWA-5461(Japanese)
http://groups.google.com/group/fj.sys.news/browse_thread/thread/a01b3e3ac6ae5b2d
SONY NEWS Info(Japanese)
http://katsu.watanabe.name/doc/sonynews/
Pinouts
-------
EIA 232 male connector from NWP-5461
-------------
\ 1 2 3 4 5 /
\ 6 7 8 9 /
---------
1 VCC
2 BZ(Speaker)
3 Keyboard Data(from keyboard MCU TxD)
4 NC
5 GND
6 Unknown Input(to keyboard MCU RxD via schmitt trigger)
7 Mouse Data(from Mouse Ext connector)
8 Unknown Input(to Keyboard MCU Input via diode and buffer)
9 FG
NOTE: Two LED on keyboard are controlled by pin 6,8?
EIA 232 male connector from NWP-411A
-------------
\ 1 2 3 4 5 /
\ 6 7 8 9 /
---------
1 VCC
2 BZ(Speaker)
3 Keyboard Data(from keyboard MCU TxD)
4 NC
5 GND
6 NC
7 Mouse Data(from Mouse Ext connector)
8 NC
9 FG
NOTE: These are just from my guess and not confirmed.
Signaling
---------
~~~~~~~~~~ ____XOO0X111X222X333X444X555X666X777~~~~ ~~~~~~~
Idle Start LSB MSB Stop Idle
Idle: High
Start bit: Low
Stop bit: High
Bit order: LSB first
Baud rate: 9600
Interface: TTL level(5V) UART
NOTE: This is observed on NWP-5461 with its DIP switch all OFF.
Format
------
MSB LSB
7 6 5 4 3 2 1 0 bit
| | | | | | | |
| +-+-+-+-+-+-+-- scan code(00-7F)
+---------------- break flag: sets when released
Scan Codes
----------
SONY NEWS NWP-5461
,---. ,------------------------, ,------------------------. ,---------.
| 7A| | 01 | 02 | 03 | 04 | 05 | | 06 | 07 | 08 | 09 | 0A | | 68 | 69 | ,-----------.
`---' `------------------------' `------------------------' `---------' | 64| 65| 52|
,-------------------------------------------------------------. ,---. ,---------------|
| 0B| 0C| 0D| 0E| 0F| 10| 11| 12| 13| 14| 15| 16| 17| 18| 19 | | 6A| | 4B| 4C| 4D| 4E|
|-------------------------------------------------------------| |---| |---------------|
| 1A | 1B| 1C| 1D| 1E| 1F| 20| 21| 22| 23| 24| 25| 26| 27| | | 6B| | 4F| 50| 51| 56|
|---------------------------------------------------------' | |---| |---------------|
| 28 | 29| 2A| 2B| 2C| 2D| 2E| 2F| 30| 31| 32| 33| 34| 35 | | 6C| | 53| 54| 55| |
|-------------------------------------------------------------| |---| |-----------| 5A|
| 36 | 37| 38| 39| 3A| 3B| 3C| 3D| 3E| 3F| 40| 41| 42 | | 6D| | 57| 59| 58| |
|-------------------------------------------------------------| |---| |---------------|
| 43 | 44 | 45 | 46 | 47 | 48| 49| 4A | | 6E| | 66| 5B| 5C| 5D|
`-------------------------------------------------------------' `---' `---------------'
*/

View file

@ -1,51 +0,0 @@
/*
Copyright 2012 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 NEWS_H
#define NEWS_H
/*
* Primitive PS/2 Library for AVR
*/
/* host role */
void news_init(void);
uint8_t news_recv(void);
/* device role */
#endif

View file

@ -59,16 +59,10 @@ static inline void query(void);
static inline void reset(void);
static inline uint32_t response(void);
/* The keyboard sends signal with 50us pulse width on OUT line
* while it seems to miss the 50us pulse on In line.
* next_kbd_set_leds() often fails to sync LED status with 50us
* but it works well with 51us(+1us) on TMK converter(ATMeaga32u2) at least.
* TODO: test on Teensy and Pro Micro configuration
*/
#define out_hi_delay(intervals) do { out_hi(); _delay_us((NEXT_KBD_TIMING+1) * intervals); } while (0);
#define out_lo_delay(intervals) do { out_lo(); _delay_us((NEXT_KBD_TIMING+1) * intervals); } while (0);
#define query_delay(intervals) do { query(); _delay_us((NEXT_KBD_TIMING+1) * intervals); } while (0);
#define reset_delay(intervals) do { reset(); _delay_us((NEXT_KBD_TIMING+1) * intervals); } while (0);
#define out_hi_delay(intervals) do { out_hi(); _delay_us((NEXT_KBD_TIMING) * intervals); } while (0);
#define out_lo_delay(intervals) do { out_lo(); _delay_us((NEXT_KBD_TIMING) * intervals); } while (0);
#define query_delay(intervals) do { query(); _delay_us((NEXT_KBD_TIMING) * intervals); } while (0);
#define reset_delay(intervals) do { reset(); _delay_us((NEXT_KBD_TIMING) * intervals); } while (0);
void next_kbd_init(void)
{
@ -144,34 +138,14 @@ static inline uint32_t response(void)
sei();
return 0;
}
_delay_us(NEXT_KBD_TIMING / 2);
_delay_us(NEXT_KBD_TIMING / 2 - 1);
for (; i < 22; i++)
{
if (NEXT_KBD_READ)
{
data |= ((uint32_t) 1 << i);
/* Note:
* My testing with the ATmega32u4 showed that there might
* something wrong with the timing here; by the end of the
* second data byte some of the modifiers can get bumped out
* to the next bit over if we just cycle through the data
* based on the expected interval. There is a bit (i = 10)
* in the middle of the data that is always on followed by
* one that is always off - so we'll use that to reset our
* timing in case we've gotten ahead of the keyboard;
*/
if (i == 10)
{
i++;
while (NEXT_KBD_READ) ;
_delay_us(NEXT_KBD_TIMING / 2);
}
} else {
/* redundant - but I don't want to remove if it might screw
* up the timing
*/
data |= ((uint32_t) 0 << i);
data |= (uint32_t)1 << 22;
}
data >>= 1;
_delay_us(NEXT_KBD_TIMING);
}

View file

@ -51,7 +51,9 @@ POSSIBILITY OF SUCH DAMAGE.
#define NEXT_KBD_H
#define NEXT_KBD_KMBUS_IDLE 0x300600
#define NEXT_KBD_TIMING 50
// https://github.com/tmk/tmk_keyboard/issues/704
#define NEXT_KBD_TIMING 52
extern uint8_t next_kbd_error;

View file

@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
static report_mouse_t mouse_report = {};
static uint8_t last_buttons;
static void print_usb_data(void);
@ -161,6 +162,7 @@ void ps2_mouse_task(void)
host_mouse_send(&mouse_report);
last_buttons = mouse_report.buttons;
print_usb_data();
}
// clear report
@ -171,6 +173,11 @@ void ps2_mouse_task(void)
mouse_report.buttons = 0;
}
uint8_t ps2_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(void)
{
if (!debug_mouse) return;

View file

@ -62,5 +62,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
uint8_t ps2_mouse_init(void);
void ps2_mouse_task(void);
uint8_t ps2_mouse_buttons(void);
#endif

View file

@ -29,5 +29,6 @@ static inline uint8_t serial_mouse_init(void)
}
void serial_mouse_task(void);
uint8_t serial_mouse_buttons(void);
#endif

View file

@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
static uint8_t last_buttons;
static void print_usb_data(const report_mouse_t *report);
void serial_mouse_task(void)
@ -71,6 +72,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
return;
}
@ -111,6 +113,12 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
uint8_t serial_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(const report_mouse_t *report)

View file

@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define SERIAL_MOUSE_CENTER_SCROLL
static uint8_t last_buttons;
static void print_usb_data(const report_mouse_t *report);
void serial_mouse_task(void)
@ -78,6 +79,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
if (buffer[3] || buffer[4]) {
report.h = MAX((int8_t)buffer[3], -127);
@ -85,6 +87,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
return;
@ -117,9 +120,15 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
}
uint8_t serial_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(const report_mouse_t *report)
{
if (!debug_mouse)

View file

@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
* TODO: delay is not accurate enough. Instruction cycle should be counted and inline assemby is needed.
*/
#define WAIT_US (1000000L/SERIAL_SOFT_BAUD)
#define WAIT_US (1000000L/SERIAL_SOFT_BAUD - 1)
#ifdef SERIAL_SOFT_LOGIC_NEGATIVE
#define SERIAL_SOFT_RXD_IN() !(SERIAL_SOFT_RXD_READ())
@ -68,11 +68,10 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
/* debug for signal timing, see debug pin with oscilloscope */
#ifdef SERIAL_SOFT_DEBUG
#define SERIAL_SOFT_DEBUG_INIT() (DDRD |= 1<<7)
#define SERIAL_SOFT_DEBUG_TGL() (PORTD ^= 1<<7)
#else
#ifndef SERIAL_SOFT_DEBUG_INIT
#define SERIAL_SOFT_DEBUG_INIT()
#endif
#ifndef SERIAL_SOFT_DEBUG_TGL
#define SERIAL_SOFT_DEBUG_TGL()
#endif
@ -86,7 +85,9 @@ void serial_init(void)
}
/* RX ring buffer */
#define RBUF_SIZE 8
#ifndef RBUF_SIZE
#define RBUF_SIZE 256
#endif
static uint8_t rbuf[RBUF_SIZE];
static uint8_t rbuf_head = 0;
static uint8_t rbuf_tail = 0;
@ -175,6 +176,9 @@ void serial_send(uint8_t data)
ISR(SERIAL_SOFT_RXD_VECT)
{
SERIAL_SOFT_DEBUG_TGL();
/* can be triggered by other pin. don't know why */
if (SERIAL_SOFT_RXD_IN()) { return; }
SERIAL_SOFT_RXD_INT_ENTER();
uint8_t data = 0;
@ -194,6 +198,7 @@ ISR(SERIAL_SOFT_RXD_VECT)
/* to center of start bit */
_delay_us(WAIT_US/2);
SERIAL_SOFT_DEBUG_TGL();
//if (SERIAL_SOFT_RXD_IN()) { return; }
do {
/* to center of next bit */
_delay_us(WAIT_US);

View file

@ -63,7 +63,9 @@ void serial_init(void)
}
// RX ring buffer
#ifndef RBUF_SIZE
#define RBUF_SIZE 256
#endif
static uint8_t rbuf[RBUF_SIZE];
static uint8_t rbuf_head = 0;
static uint8_t rbuf_tail = 0;

View file

@ -12,6 +12,10 @@ USB_HOST_SHIELD_SRC = \
$(USB_HOST_SHIELD_DIR)/parsetools.cpp \
$(USB_HOST_SHIELD_DIR)/message.cpp
# Version string
TMK_USB_HOST_SHIELD_VERSION := $(shell (cd $(TMK_DIR)/$(USB_HOST_SHIELD_DIR); git rev-parse --short=6 HEAD || echo 'unknown') 2> /dev/null)
OPT_DEFS += -DTMK_USB_HOST_SHIELD_VERSION=$(TMK_USB_HOST_SHIELD_VERSION)
#

View file

@ -51,8 +51,10 @@ size_t Serial_::write(uint8_t c)
size_t Serial_::write(const uint8_t *buffer, size_t size)
{
sendchar(*buffer);
return 1;
for (int i = 0; i < size; i++) {
sendchar(buffer[i]);
}
return size;
}
Serial_::operator bool() {

View file

@ -12,6 +12,15 @@ void KBDReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *b
}
xprintf("\r\n");
/* Keyboard can send report in size other than 8 bytes
* https://github.com/tmk/tmk_keyboard/issues/773
// boot keyboard report length should be 8
if (len != 8) {
xprintf(" ignored\r\n");
return;
}
*/
// Rollover error
// Cherry: 0101010101010101
// https://geekhack.org/index.php?topic=69169.msg2638223#msg2638223