summaryrefslogtreecommitdiffstats
path: root/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'protocol')
-rw-r--r--protocol/adb.c18
-rw-r--r--protocol/lufa/lufa.c13
-rw-r--r--protocol/pjrc.mk6
-rw-r--r--protocol/pjrc/usb.c3
-rw-r--r--protocol/ps2.h146
-rw-r--r--protocol/ps2_busywait.c185
-rw-r--r--protocol/ps2_interrupt.c (renamed from protocol/ps2.c)321
-rw-r--r--protocol/ps2_mouse.c303
-rw-r--r--protocol/ps2_mouse.h40
-rw-r--r--protocol/ps2_usart.c224
10 files changed, 657 insertions, 602 deletions
diff --git a/protocol/adb.c b/protocol/adb.c
index 750f4b9650..a4783f36e5 100644
--- a/protocol/adb.c
+++ b/protocol/adb.c
@@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <avr/io.h>
#include <avr/interrupt.h>
#include "adb.h"
-#include "debug.h"
// GCC doesn't inline functions normally
@@ -125,16 +124,15 @@ bool adb_host_psw(void)
uint16_t adb_host_kbd_recv(void)
{
uint16_t data = 0;
+ cli();
attention();
send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
place_bit0(); // Stopbit(0)
if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us)
+ sei();
return 0; // No data to send
}
- // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck
- // TODO: is this needed anymore with improved timing?
- //cli();
uint8_t n = 17; // start bit + 16 data bits
do {
uint8_t lo = (uint8_t) wait_data_hi(130);
@@ -153,10 +151,8 @@ uint16_t adb_host_kbd_recv(void)
data |= 1;
}
else if (n == 17) {
- // Service Request
- dprintf("Startbit ERROR\n");
sei();
- return -2;
+ return -20;
}
}
while ( --n );
@@ -164,21 +160,20 @@ uint16_t adb_host_kbd_recv(void)
// Stop bit can't be checked normally since it could have service request lenghtening
// and its high state never goes low.
if (!wait_data_hi(351) || wait_data_lo(91)) {
- dprintf("Stopbit ERROR\n");
sei();
- return -3;
+ return -21;
}
sei();
return data;
error:
- dprintf("Bit ERROR\n");
sei();
- return -4;
+ return -n;
}
void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l)
{
+ cli();
attention();
send_byte(cmd);
place_bit0(); // Stopbit(0)
@@ -187,6 +182,7 @@ void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l)
send_byte(data_h);
send_byte(data_l);
place_bit0(); // Stopbit(0);
+ sei();
}
// send state of LEDs
diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c
index a230d5ba20..eca51c8784 100644
--- a/protocol/lufa/lufa.c
+++ b/protocol/lufa/lufa.c
@@ -148,7 +148,6 @@ static void Console_Task(void)
*/
void EVENT_USB_Device_Connect(void)
{
- led_set(0x1f); // all on
}
void EVENT_USB_Device_Disconnect(void)
@@ -172,8 +171,9 @@ void EVENT_USB_Device_WakeUp()
#ifdef SLEEP_LED_ENABLE
sleep_led_disable();
-#endif
+ // NOTE: converters may not accept this
led_set(host_keyboard_leds());
+#endif
}
void EVENT_USB_Device_StartOfFrame(void)
@@ -539,11 +539,18 @@ int main(void)
{
SetupHardware();
sei();
+
+ /* wait for USB startup & debug output */
+ while (USB_DeviceState != DEVICE_STATE_Configured) {
#if defined(INTERRUPT_CONTROL_ENDPOINT)
- while (USB_DeviceState != DEVICE_STATE_Configured) ;
+ ;
+#else
+ USB_USBTask();
#endif
+ }
print("USB configured.\n");
+ /* init modules */
keyboard_init();
host_set_driver(&lufa_driver);
#ifdef SLEEP_LED_ENABLE
diff --git a/protocol/pjrc.mk b/protocol/pjrc.mk
index 27f908b1c2..5a44613820 100644
--- a/protocol/pjrc.mk
+++ b/protocol/pjrc.mk
@@ -7,7 +7,11 @@ SRC += $(PJRC_DIR)/main.c \
$(PJRC_DIR)/usb.c
# Option modules
-ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
+ifdef MOUSEKEY_ENABLE
+ SRC += $(PJRC_DIR)/usb_mouse.c
+endif
+
+ifdef PS2_MOUSE_ENABLE
SRC += $(PJRC_DIR)/usb_mouse.c
endif
diff --git a/protocol/pjrc/usb.c b/protocol/pjrc/usb.c
index 84c99972f2..393b36f78e 100644
--- a/protocol/pjrc/usb.c
+++ b/protocol/pjrc/usb.c
@@ -662,8 +662,9 @@ ISR(USB_GEN_vect)
suspend_wakeup_init();
#ifdef SLEEP_LED_ENABLE
sleep_led_disable();
-#endif
+ // NOTE: converters may not accept this
led_set(host_keyboard_leds());
+#endif
UDIEN |= (1<<SUSPE);
UDIEN &= ~(1<<WAKEUPE);
diff --git a/protocol/ps2.h b/protocol/ps2.h
index 834165356c..483eea7209 100644
--- a/protocol/ps2.h
+++ b/protocol/ps2.h
@@ -1,5 +1,5 @@
/*
-Copyright 2010,2011 Jun WAKO <wakojun@gmail.com>
+Copyright 2010,2011,2012,2013 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,
@@ -37,32 +37,46 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef PS2_H
#define PS2_H
+
+#include <stdbool.h>
+#include <util/delay.h>
+#include <avr/io.h>
+
/*
* Primitive PS/2 Library for AVR
+ *
+ * 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
*/
-
-
-/* port settings for clock and data line */
-#if !(defined(PS2_CLOCK_PORT) && \
- defined(PS2_CLOCK_PIN) && \
- defined(PS2_CLOCK_DDR) && \
- defined(PS2_CLOCK_BIT))
-# error "PS/2 clock port setting is required in config.h"
-#endif
-
-#if !(defined(PS2_DATA_PORT) && \
- defined(PS2_DATA_PIN) && \
- defined(PS2_DATA_DDR) && \
- defined(PS2_DATA_BIT))
-# error "PS/2 data port setting is required in config.h"
-#endif
-
#define PS2_ACK 0xFA
#define PS2_RESEND 0xFE
#define PS2_SET_LED 0xED
-#define PS2_ERR_NONE 0
-#define PS2_ERR_PARITY 0x10
+// TODO: error numbers
+#define PS2_ERR_NONE 0
+#define PS2_ERR_STARTBIT1 1
+#define PS2_ERR_STARTBIT2 2
+#define PS2_ERR_STARTBIT3 3
+#define PS2_ERR_PARITY 0x10
+#define PS2_ERR_NODATA 0x20
#define PS2_LED_SCROLL_LOCK 0
#define PS2_LED_NUM_LOCK 1
@@ -71,13 +85,101 @@ POSSIBILITY OF SUCH DAMAGE.
extern uint8_t ps2_error;
-/* host role */
void ps2_host_init(void);
uint8_t ps2_host_send(uint8_t data);
uint8_t ps2_host_recv_response(void);
uint8_t ps2_host_recv(void);
void ps2_host_set_led(uint8_t usb_led);
-/* device role */
+
+/* Check port settings for clock and data line */
+#if !(defined(PS2_CLOCK_PORT) && \
+ defined(PS2_CLOCK_PIN) && \
+ defined(PS2_CLOCK_DDR) && \
+ defined(PS2_CLOCK_BIT))
+# error "PS/2 clock port setting is required in config.h"
+#endif
+
+#if !(defined(PS2_DATA_PORT) && \
+ defined(PS2_DATA_PIN) && \
+ defined(PS2_DATA_DDR) && \
+ defined(PS2_DATA_BIT))
+# error "PS/2 data port setting is required in config.h"
+#endif
+
+/*--------------------------------------------------------------------
+ * static functions
+ *------------------------------------------------------------------*/
+static inline void clock_lo(void)
+{
+ PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
+ PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
+}
+static inline void clock_hi(void)
+{
+ /* input with pull up */
+ PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
+ PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
+}
+static inline bool clock_in(void)
+{
+ PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
+ PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
+ _delay_us(1);
+ return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
+}
+static inline void data_lo(void)
+{
+ PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
+ PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
+}
+static inline void data_hi(void)
+{
+ /* input with pull up */
+ PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
+ PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
+}
+static inline bool data_in(void)
+{
+ PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
+ PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
+ _delay_us(1);
+ return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
+}
+
+static inline uint16_t wait_clock_lo(uint16_t us)
+{
+ while (clock_in() && us) { asm(""); _delay_us(1); us--; }
+ return us;
+}
+static inline uint16_t wait_clock_hi(uint16_t us)
+{
+ while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
+ return us;
+}
+static inline uint16_t wait_data_lo(uint16_t us)
+{
+ while (data_in() && us) { asm(""); _delay_us(1); us--; }
+ return us;
+}
+static inline uint16_t wait_data_hi(uint16_t us)
+{
+ while (!data_in() && us) { asm(""); _delay_us(1); us--; }
+ return us;
+}
+
+/* idle state that device can send */
+static inline void idle(void)
+{
+ clock_hi();
+ data_hi();
+}
+
+/* inhibit device to send */
+static inline void inhibit(void)
+{
+ clock_lo();
+ data_hi();
+}
#endif
diff --git a/protocol/ps2_busywait.c b/protocol/ps2_busywait.c
new file mode 100644
index 0000000000..05dd7b27e6
--- /dev/null
+++ b/protocol/ps2_busywait.c
@@ -0,0 +1,185 @@
+/*
+Copyright 2010,2011,2012,2013 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.
+*/
+
+/*
+ * PS/2 protocol busywait version
+ */
+
+#include <stdbool.h>
+#include <util/delay.h>
+#include "ps2.h"
+#include "debug.h"
+
+
+#define WAIT(stat, us, err) do { \
+ if (!wait_##stat(us)) { \
+ ps2_error = err; \
+ goto ERROR; \
+ } \
+} while (0)
+
+
+uint8_t ps2_error = PS2_ERR_NONE;
+
+
+void ps2_host_init(void)
+{
+ // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
+ _delay_ms(2500);
+
+ inhibit();
+}
+
+uint8_t ps2_host_send(uint8_t data)
+{
+ bool parity = true;
+ ps2_error = PS2_ERR_NONE;
+
+ /* terminate a transmission if we have */
+ inhibit();
+ _delay_us(100); // 100us [4]p.13, [5]p.50
+
+ /* 'Request to Send' and Start bit */
+ data_lo();
+ clock_hi();
+ WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
+
+ /* Data bit */
+ for (uint8_t i = 0; i < 8; i++) {
+ _delay_us(15);
+ if (data&(1<<i)) {
+ parity = !parity;
+ data_hi();
+ } else {
+ data_lo();
+ }
+ WAIT(clock_hi, 50, 2);
+ WAIT(clock_lo, 50, 3);
+ }
+
+ /* Parity bit */
+ _delay_us(15);
+ if (parity) { data_hi(); } else { data_lo(); }
+ WAIT(clock_hi, 50, 4);
+ WAIT(clock_lo, 50, 5);
+
+ /* Stop bit */
+ _delay_us(15);
+ data_hi();
+
+ /* Ack */
+ WAIT(data_lo, 50, 6);
+ WAIT(clock_lo, 50, 7);
+
+ /* wait for idle state */
+ WAIT(clock_hi, 50, 8);
+ WAIT(data_hi, 50, 9);
+
+ inhibit();
+ return ps2_host_recv_response();
+ERROR:
+ inhibit();
+ return 0;
+}
+
+/* receive data when host want else inhibit communication */
+uint8_t ps2_host_recv_response(void)
+{
+ // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
+ // 250 * 100us(wait for start bit in ps2_host_recv)
+ uint8_t data = 0;
+ uint8_t try = 250;
+ do {
+ data = ps2_host_recv();
+ } while (try-- && ps2_error);
+ return data;
+}
+
+/* called after start bit comes */
+uint8_t ps2_host_recv(void)
+{
+ uint8_t data = 0;
+ bool parity = true;
+ ps2_error = PS2_ERR_NONE;
+
+ /* release lines(idle state) */
+ idle();
+
+ /* start bit [1] */
+ WAIT(clock_lo, 100, 1); // TODO: this is enough?
+ WAIT(data_lo, 1, 2);
+ WAIT(clock_hi, 50, 3);
+
+ /* data [2-9] */
+ for (uint8_t i = 0; i < 8; i++) {
+ WAIT(clock_lo, 50, 4);
+ if (data_in()) {
+ parity = !parity;
+ data |= (1<<i);
+ }
+ WAIT(clock_hi, 50, 5);
+ }
+
+ /* parity [10] */
+ WAIT(clock_lo, 50, 6);
+ if (data_in() != parity) {
+ ps2_error = PS2_ERR_PARITY;
+ goto ERROR;
+ }
+ WAIT(clock_hi, 50, 7);
+
+ /* stop bit [11] */
+ WAIT(clock_lo, 50, 8);
+ WAIT(data_hi, 1, 9);
+ WAIT(clock_hi, 50, 10);
+
+ inhibit();
+ return data;
+ERROR:
+ if (ps2_error > PS2_ERR_STARTBIT3) {
+ xprintf("x%02X\n", ps2_error);
+ }
+ inhibit();
+ return 0;
+}
+
+/* send LED state to keyboard */
+void ps2_host_set_led(uint8_t led)
+{
+ ps2_host_send(0xED);
+ ps2_host_send(led);
+}
diff --git a/protocol/ps2.c b/protocol/ps2_interrupt.c
index ed45609104..259d254007 100644
--- a/protocol/ps2.c
+++ b/protocol/ps2_interrupt.c
@@ -1,5 +1,5 @@
/*
-Copyright 2010,2011 Jun WAKO <wakojun@gmail.com>
+Copyright 2010,2011,2012,2013 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,
@@ -35,45 +35,15 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * PS/2 protocol Pin interrupt version
+ */
+
#include <stdbool.h>
-#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "ps2.h"
-#include "debug.h"
-
-
-static uint8_t recv_data(void);
-static inline void clock_lo(void);
-static inline void clock_hi(void);
-static inline bool clock_in(void);
-static inline void data_lo(void);
-static inline void data_hi(void);
-static inline bool data_in(void);
-static inline uint16_t wait_clock_lo(uint16_t us);
-static inline uint16_t wait_clock_hi(uint16_t us);
-static inline uint16_t wait_data_lo(uint16_t us);
-static inline uint16_t wait_data_hi(uint16_t us);
-static inline void idle(void);
-static inline void inhibit(void);
-
-
-/*
-Primitive PS/2 Library for AVR
-==============================
-Host side is only supported now.
-
-
-I/O control
------------
-High state is asserted by input with pull up.
-
-
-PS/2 References
----------------
-http://www.computer-engineering.org/ps2protocol/
-http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
-*/
+#include "print.h"
#define WAIT(stat, us, err) do { \
@@ -87,35 +57,38 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
uint8_t ps2_error = PS2_ERR_NONE;
+static inline uint8_t pbuf_dequeue(void);
+static inline void pbuf_enqueue(uint8_t data);
+static inline bool pbuf_has_data(void);
+static inline void pbuf_clear(void);
+
+
void ps2_host_init(void)
{
-#ifdef PS2_USE_INT
+ idle();
PS2_INT_INIT();
PS2_INT_ON();
- idle();
-#else
- inhibit();
-#endif
+ // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
+ //_delay_ms(2500);
}
-// TODO: send using interrupt if available
uint8_t ps2_host_send(uint8_t data)
{
- uint8_t res = 0;
bool parity = true;
ps2_error = PS2_ERR_NONE;
-#ifdef PS2_USE_INT
+
PS2_INT_OFF();
-#endif
+
/* terminate a transmission if we have */
inhibit();
- _delay_us(100);
+ _delay_us(100); // 100us [4]p.13, [5]p.50
- /* start bit [1] */
+ /* 'Request to Send' and Start bit */
data_lo();
clock_hi();
- WAIT(clock_lo, 15000, 1);
- /* data [2-9] */
+ WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
+
+ /* Data bit[2-9] */
for (uint8_t i = 0; i < 8; i++) {
_delay_us(15);
if (data&(1<<i)) {
@@ -127,15 +100,18 @@ uint8_t ps2_host_send(uint8_t data)
WAIT(clock_hi, 50, 2);
WAIT(clock_lo, 50, 3);
}
- /* parity [10] */
+
+ /* Parity bit */
_delay_us(15);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_hi, 50, 4);
WAIT(clock_lo, 50, 5);
- /* stop bit [11] */
+
+ /* Stop bit */
_delay_us(15);
data_hi();
- /* ack [12] */
+
+ /* Ack */
WAIT(data_lo, 50, 6);
WAIT(clock_lo, 50, 7);
@@ -143,99 +119,37 @@ uint8_t ps2_host_send(uint8_t data)
WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9);
- res = ps2_host_recv_response();
-ERROR:
-#ifdef PS2_USE_INT
+ idle();
PS2_INT_ON();
+ return ps2_host_recv_response();
+ERROR:
idle();
-#else
- inhibit();
-#endif
- return res;
+ PS2_INT_ON();
+ return 0;
}
-/* receive data when host want else inhibit communication */
uint8_t ps2_host_recv_response(void)
{
- uint8_t data = 0;
-
- /* terminate a transmission if we have */
- inhibit();
- _delay_us(100);
-
- /* release lines(idle state) */
- idle();
-
- /* wait start bit */
- wait_clock_lo(2000);
- data = recv_data();
-
- inhibit();
- return data;
-}
-
-#ifndef PS2_USE_INT
-uint8_t ps2_host_recv(void)
-{
- return ps2_host_recv_response();
-}
-#else
-/* ring buffer to store ps/2 key data */
-#define PBUF_SIZE 32
-static uint8_t pbuf[PBUF_SIZE];
-static uint8_t pbuf_head = 0;
-static uint8_t pbuf_tail = 0;
-static inline void pbuf_enqueue(uint8_t data)
-{
- if (!data)
- return;
-
- uint8_t sreg = SREG;
- cli();
- uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
- if (next != pbuf_tail) {
- pbuf[pbuf_head] = data;
- pbuf_head = next;
- } else {
- debug("pbuf: full\n");
- }
- SREG = sreg;
-}
-static inline uint8_t pbuf_dequeue(void)
-{
- uint8_t val = 0;
-
- uint8_t sreg = SREG;
- cli();
- if (pbuf_head != pbuf_tail) {
- val = pbuf[pbuf_tail];
- pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
+ // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
+ uint8_t retry = 25;
+ while (retry-- && !pbuf_has_data()) {
+ _delay_ms(1);
}
- SREG = sreg;
-
- return val;
+ return pbuf_dequeue();
}
/* get data received by interrupt */
uint8_t ps2_host_recv(void)
{
- if (ps2_error) {
- print("x");
- phex(ps2_error);
- ps2_host_send(0xFE); // request to resend
+ if (pbuf_has_data()) {
ps2_error = PS2_ERR_NONE;
+ return pbuf_dequeue();
+ } else {
+ ps2_error = PS2_ERR_NODATA;
+ return 0;
}
- idle();
- return pbuf_dequeue();
}
-#if 0
-#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
-#define DEBUGP(x) do { PORTC = x; } while (0)
-#else
-#define DEBUGP_INIT()
-#define DEBUGP(x)
-#endif
ISR(PS2_INT_VECT)
{
static enum {
@@ -256,7 +170,6 @@ ISR(PS2_INT_VECT)
}
state++;
- DEBUGP(state);
switch (state) {
case START:
if (data_in())
@@ -296,8 +209,6 @@ ISR(PS2_INT_VECT)
}
goto RETURN;
ERROR:
- DEBUGP(0x0F);
- inhibit();
ps2_error = state;
DONE:
state = INIT;
@@ -306,13 +217,6 @@ DONE:
RETURN:
return;
}
-#endif
-
-
-static void ps2_reset(void)
-{
- ps2_host_send(0xFF);
-}
/* send LED state to keyboard */
void ps2_host_set_led(uint8_t led)
@@ -322,114 +226,53 @@ void ps2_host_set_led(uint8_t led)
}
-/* called after start bit comes */
-static uint8_t recv_data(void)
+/*--------------------------------------------------------------------
+ * Ring buffer to store scan codes from keyboard
+ *------------------------------------------------------------------*/
+#define PBUF_SIZE 32
+static uint8_t pbuf[PBUF_SIZE];
+static uint8_t pbuf_head = 0;
+static uint8_t pbuf_tail = 0;
+static inline void pbuf_enqueue(uint8_t data)
{
- uint8_t data = 0;
- bool parity = true;
- ps2_error = PS2_ERR_NONE;
-
- /* start bit [1] */
- WAIT(clock_lo, 1, 1);
- WAIT(data_lo, 1, 2);
- WAIT(clock_hi, 50, 3);
-
- /* data [2-9] */
- for (uint8_t i = 0; i < 8; i++) {
- WAIT(clock_lo, 50, 4);
- if (data_in()) {
- parity = !parity;
- data |= (1<<i);
- }
- WAIT(clock_hi, 50, 5);
- }
-
- /* parity [10] */
- WAIT(clock_lo, 50, 6);
- if (data_in() != parity) {
- ps2_error = PS2_ERR_PARITY;
- goto ERROR;
+ uint8_t sreg = SREG;
+ cli();
+ uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
+ if (next != pbuf_tail) {
+ pbuf[pbuf_head] = data;
+ pbuf_head = next;
+ } else {
+ print("pbuf: full\n");
}
- WAIT(clock_hi, 50, 7);
-
- /* stop bit [11] */
- WAIT(clock_lo, 50, 8);
- WAIT(data_hi, 1, 9);
- WAIT(clock_hi, 50, 10);
-
- return data;
-ERROR:
- return 0;
-}
-
-static inline void clock_lo()
-{
- PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
- PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
-}
-static inline void clock_hi()
-{
- /* input with pull up */
- PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
- PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
-}
-static inline bool clock_in()
-{
- PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
- PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
- _delay_us(1);
- return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
-}
-static inline void data_lo()
-{
- PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
- PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
-}
-static inline void data_hi()
-{
- /* input with pull up */
- PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
- PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
+ SREG = sreg;
}
-static inline bool data_in()
+static inline uint8_t pbuf_dequeue(void)
{
- PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
- PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
- _delay_us(1);
- return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
-}
+ uint8_t val = 0;
-static inline uint16_t wait_clock_lo(uint16_t us)
-{
- while (clock_in() && us) { asm(""); _delay_us(1); us--; }
- return us;
-}
-static inline uint16_t wait_clock_hi(uint16_t us)
-{
- while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
- return us;
-}
-static inline uint16_t wait_data_lo(uint16_t us)
-{
- while (data_in() && us) { asm(""); _delay_us(1); us--; }
- return us;
+ uint8_t sreg = SREG;
+ cli();
+ if (pbuf_head != pbuf_tail) {
+ val = pbuf[pbuf_tail];
+ pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
+ }
+ SREG = sreg;
+
+ return val;
}
-static inline uint16_t wait_data_hi(uint16_t us)
+static inline bool pbuf_has_data(void)
{
- while (!data_in() && us) { asm(""); _delay_us(1); us--; }
- return us;
+ uint8_t sreg = SREG;
+ cli();
+ bool has_data = (pbuf_head != pbuf_tail);
+ SREG = sreg;
+ return has_data;
}
-
-/* idle state that device can send */
-static inline void idle(void)
+static inline void pbuf_clear(void)
{
- clock_hi();
- data_hi();
+ uint8_t sreg = SREG;
+ cli();
+ pbuf_head = pbuf_tail = 0;
+ SREG = sreg;
}
-/* inhibit device to send */
-static inline void inhibit(void)
-{
- clock_lo();
- data_hi();
-}
diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c
index f796b2b4de..4702f12c40 100644
--- a/protocol/ps2_mouse.c
+++ b/protocol/ps2_mouse.c
@@ -1,5 +1,5 @@
/*
-Copyright 2011 Jun Wako <wakojun@gmail.com>
+Copyright 2011,2013 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,199 +20,196 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include<util/delay.h>
#include "ps2.h"
#include "ps2_mouse.h"
-#include "usb_mouse.h"
+#include "report.h"
+#include "host.h"
+#include "timer.h"
+#include "print.h"
+#include "debug.h"
-#define PS2_MOUSE_DEBUG
-#ifdef PS2_MOUSE_DEBUG
-# include "print.h"
-# include "debug.h"
-#else
-# define print(s)
-# define phex(h)
-# define phex16(h)
-#endif
-// disable when errors occur 255 times.
-#define ERROR_RETURN() do { \
- if (ps2_error) { \
- if (ps2_mouse_error_count < 255) { \
- ps2_mouse_error_count++; \
- } else { \
- ps2_mouse_error_count = 0; \
- ps2_mouse_enable = false; \
- } \
- return ps2_error; \
- } \
-} while (0)
+static report_mouse_t mouse_report = {};
-/*
-TODO
-----
-- Stream mode
-- Tracpoint command support: needed
-- Middle button + move = Wheel traslation
-*/
-bool ps2_mouse_enable = true;
-uint8_t ps2_mouse_x = 0;
-uint8_t ps2_mouse_y = 0;
-uint8_t ps2_mouse_btn = 0;
-uint8_t ps2_mouse_error_count = 0;
-
-static uint8_t ps2_mouse_btn_prev = 0;
+static void print_usb_data(void);
+/* supports only 3 button mouse at this time */
uint8_t ps2_mouse_init(void) {
uint8_t rcv;
- if (!ps2_mouse_enable) return 1;
-
ps2_host_init();
- // Reset
- rcv = ps2_host_send(0xFF);
- print("ps2_mouse_init: send 0xFF: ");
- phex(ps2_error); print("\n");
- ERROR_RETURN();
+ _delay_ms(1000); // wait for powering up
- // ACK
- rcv = ps2_host_recv();
- print("ps2_mouse_init: read ACK: ");
+ // send Reset
+ rcv = ps2_host_send(0xFF);
+ print("ps2_mouse_init: send Reset: ");
phex(rcv); phex(ps2_error); print("\n");
- ERROR_RETURN();
- // BAT takes some time
- _delay_ms(100);
- rcv = ps2_host_recv();
+ // read completion code of BAT
+ rcv = ps2_host_recv_response();
print("ps2_mouse_init: read BAT: ");
phex(rcv); phex(ps2_error); print("\n");
- ERROR_RETURN();
- // Device ID
- rcv = ps2_host_recv();
+ // read Device ID
+ rcv = ps2_host_recv_response();
print("ps2_mouse_init: read DevID: ");
phex(rcv); phex(ps2_error); print("\n");
- ERROR_RETURN();
- // Enable data reporting
- ps2_host_send(0xF4);
- print("ps2_mouse_init: send 0xF4: ");
- phex(ps2_error); print("\n");
- ERROR_RETURN();
-
- // ACK
- rcv = ps2_host_recv();
- print("ps2_mouse_init: read ACK: ");
- phex(rcv); phex(ps2_error); print("\n");
- ERROR_RETURN();
-
- // Set Remote mode
- ps2_host_send(0xF0);
+ // send Set Remote mode
+ rcv = ps2_host_send(0xF0);
print("ps2_mouse_init: send 0xF0: ");
- phex(ps2_error); print("\n");
- ERROR_RETURN();
-
- // ACK
- rcv = ps2_host_recv();
- print("ps2_mouse_init: read ACK: ");
phex(rcv); phex(ps2_error); print("\n");
- ERROR_RETURN();
return 0;
}
-/*
-Data format:
- bit: 7 6 5 4 3 2 1 0
------------------------------------------------------------------------
-0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left
-1 x: X movement(0-255)
-2 y: Y movement(0-255)
-*/
-uint8_t ps2_mouse_read(void)
+#define X_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_X_SIGN))
+#define Y_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_Y_SIGN))
+#define X_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_X_OVFLW))
+#define Y_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_Y_OVFLW))
+void ps2_mouse_task(void)
{
+ enum { SCROLL_NONE, SCROLL_BTN, SCROLL_SENT };
+ static uint8_t scroll_state = SCROLL_NONE;
+ static uint8_t buttons_prev = 0;
+
+ /* receives packet from mouse */
uint8_t rcv;
+ rcv = ps2_host_send(PS2_MOUSE_READ_DATA);
+ if (rcv == PS2_ACK) {
+ mouse_report.buttons = ps2_host_recv_response();
+ mouse_report.x = ps2_host_recv_response();
+ mouse_report.y = ps2_host_recv_response();
+ } else {
+ if (!debug_mouse) print("ps2_mouse: fail to get mouse packet\n");
+ return;
+ }
- if (!ps2_mouse_enable) return 1;
+ /* if mouse moves or buttons state changes */
+ if (mouse_report.x || mouse_report.y ||
+ ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) {
- ps2_host_send(0xEB);
- ERROR_RETURN();
+#ifdef PS2_MOUSE_DEBUG
+ print("ps2_mouse raw: [");
+ phex(mouse_report.buttons); print("|");
+ print_hex8((uint8_t)mouse_report.x); print(" ");
+ print_hex8((uint8_t)mouse_report.y); print("]\n");
+#endif
- rcv=ps2_host_recv();
- ERROR_RETURN();
+ buttons_prev = mouse_report.buttons;
+