Browse Source

Merge branch 'ps2_mouse_fix'

tags/v1.9
tmk 10 years ago
parent
commit
772ab7025d

+ 1
- 10
common.mk View File

ifdef MOUSEKEY_ENABLE ifdef MOUSEKEY_ENABLE
SRC += $(COMMON_DIR)/mousekey.c SRC += $(COMMON_DIR)/mousekey.c
OPT_DEFS += -DMOUSEKEY_ENABLE OPT_DEFS += -DMOUSEKEY_ENABLE
OPT_DEFS += -DMOUSE_ENABLE
endif endif


ifdef EXTRAKEY_ENABLE ifdef EXTRAKEY_ENABLE
OPT_DEFS += -DNKRO_ENABLE OPT_DEFS += -DNKRO_ENABLE
endif endif


ifdef PS2_MOUSE_ENABLE
SRC += $(COMMON_DIR)/ps2.c \
$(COMMON_DIR)/ps2_mouse.c
OPT_DEFS += -DPS2_MOUSE_ENABLE
endif

ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
OPT_DEFS += -DMOUSE_ENABLE
endif

ifdef SLEEP_LED_ENABLE ifdef SLEEP_LED_ENABLE
SRC += $(COMMON_DIR)/sleep_led.c SRC += $(COMMON_DIR)/sleep_led.c
OPT_DEFS += -DSLEEP_LED_ENABLE OPT_DEFS += -DSLEEP_LED_ENABLE

+ 0
- 6
common/action.c View File

#endif #endif
} }


bool sending_anykey(void)
{
return (has_anykey() || host_mouse_in_use() ||
host_last_sysytem_report() || host_last_consumer_report());
}

bool is_tap_key(key_t key) bool is_tap_key(key_t key)
{ {
action_t action = layer_switch_get_action(key); action_t action = layer_switch_get_action(key);

+ 0
- 1
common/action.h View File

//void set_mods(uint8_t mods); //void set_mods(uint8_t mods);
void clear_keyboard(void); void clear_keyboard(void);
void clear_keyboard_but_mods(void); void clear_keyboard_but_mods(void);
bool sending_anykey(void);
void layer_switch(uint8_t new_layer); void layer_switch(uint8_t new_layer);
bool is_tap_key(key_t key); bool is_tap_key(key_t key);



+ 1
- 0
common/action_util.h View File

#define ACTION_UTIL_H #define ACTION_UTIL_H


#include <stdint.h> #include <stdint.h>
#include "report.h"


extern report_keyboard_t *keyboard_report; extern report_keyboard_t *keyboard_report;



+ 0
- 8
common/host.c View File

bool keyboard_nkro = false; bool keyboard_nkro = false;
#endif #endif


report_mouse_t mouse_report = {};


static host_driver_t *driver; static host_driver_t *driver;
static uint16_t last_system_report = 0; static uint16_t last_system_report = 0;
static uint16_t last_consumer_report = 0; static uint16_t last_consumer_report = 0;
(*driver->send_consumer)(report); (*driver->send_consumer)(report);
} }


uint8_t host_mouse_in_use(void)
{
return (mouse_report.buttons | mouse_report.x | mouse_report.y | mouse_report.v | mouse_report.h);
}

uint16_t host_last_sysytem_report(void) uint16_t host_last_sysytem_report(void)
{ {
return last_system_report; return last_system_report;

+ 0
- 6
common/host.h View File

extern bool keyboard_nkro; extern bool keyboard_nkro;
#endif #endif


/* report */
extern report_mouse_t mouse_report;



/* host driver */ /* host driver */
void host_set_driver(host_driver_t *driver); void host_set_driver(host_driver_t *driver);
void host_system_send(uint16_t data); void host_system_send(uint16_t data);
void host_consumer_send(uint16_t data); void host_consumer_send(uint16_t data);


/* mouse report utils */
uint8_t host_mouse_in_use(void);

uint16_t host_last_sysytem_report(void); uint16_t host_last_sysytem_report(void);
uint16_t host_last_consumer_report(void); uint16_t host_last_consumer_report(void);



+ 12
- 1
common/keyboard.c View File

#include "sendchar.h" #include "sendchar.h"
#include "bootmagic.h" #include "bootmagic.h"
#include "eeconfig.h" #include "eeconfig.h"
#include "mousekey.h"
#include "backlight.h" #include "backlight.h"
#ifdef MOUSEKEY_ENABLE
# include "mousekey.h"
#endif
#ifdef PS2_MOUSE_ENABLE
# include "ps2_mouse.h"
#endif




#ifdef MATRIX_HAS_GHOST #ifdef MATRIX_HAS_GHOST
action_exec(TICK); action_exec(TICK);


MATRIX_LOOP_END: MATRIX_LOOP_END:

#ifdef MOUSEKEY_ENABLE #ifdef MOUSEKEY_ENABLE
// mousekey repeat & acceleration // mousekey repeat & acceleration
mousekey_task(); mousekey_task();
#endif #endif

#ifdef PS2_MOUSE_ENABLE
ps2_mouse_task();
#endif

// update LED // update LED
if (led_status != host_keyboard_leds()) { if (led_status != host_keyboard_leds()) {
led_status = host_keyboard_leds(); led_status = host_keyboard_leds();

+ 1
- 0
common/mousekey.c View File







static report_mouse_t mouse_report = {};
static uint8_t mousekey_repeat = 0; static uint8_t mousekey_repeat = 0;
static uint8_t mousekey_accel = 0; static uint8_t mousekey_accel = 0;



+ 12
- 21
keyboard/onekey/Makefile.lufa View File

F_USB = $(F_CPU) F_USB = $(F_CPU)


# Interrupt driven control endpoint task(+60) # Interrupt driven control endpoint task(+60)
#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT




# Boot Section Size in *bytes* # Boot Section Size in *bytes*
# Build Options # Build Options
# comment out to disable the options. # comment out to disable the options.
# #
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
#MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
#EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400) CONSOLE_ENABLE = yes # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
#COMMAND_ENABLE = yes # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA #NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA


PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
PS2_USE_BUSYWAIT = yes # uses primitive reference code
#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin
#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened)


# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax


# Search Path # Search Path
VPATH += $(TARGET_DIR) VPATH += $(TARGET_DIR)
VPATH += $(TOP_DIR) VPATH += $(TOP_DIR)


include $(TOP_DIR)/protocol/lufa.mk
include $(TOP_DIR)/common.mk include $(TOP_DIR)/common.mk
include $(TOP_DIR)/protocol.mk
include $(TOP_DIR)/protocol/lufa.mk
include $(TOP_DIR)/rules.mk include $(TOP_DIR)/rules.mk

plain: OPT_DEFS += -DKEYMAP_PLAIN
plain: all

poker: OPT_DEFS += -DKEYMAP_POKER
poker: all

poker_set: OPT_DEFS += -DKEYMAP_POKER_SET
poker_set: all

poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT
poker_bit: all

+ 13
- 20
keyboard/onekey/Makefile.pjrc View File

# Build Options # Build Options
# comment out to disable the options. # comment out to disable the options.
# #
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes # Mouse keys(+5000)
EXTRAKEY_ENABLE = yes # Audio control and System control(+600)
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
#MOUSEKEY_ENABLE = yes # Mouse keys(+5000)
#EXTRAKEY_ENABLE = yes # Audio control and System control(+600)
CONSOLE_ENABLE = yes # Console for debug CONSOLE_ENABLE = yes # Console for debug
COMMAND_ENABLE = yes # Commands for debug and configuration
SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
NKRO_ENABLE = yes # USB Nkey Rollover(+500)
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
#COMMAND_ENABLE = yes # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
#NKRO_ENABLE = yes # USB Nkey Rollover(+500)

PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
PS2_USE_BUSYWAIT = yes # uses primitive reference code
#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin
#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened)




# Search Path # Search Path
VPATH += $(TARGET_DIR) VPATH += $(TARGET_DIR)
VPATH += $(TOP_DIR) VPATH += $(TOP_DIR)


include $(TOP_DIR)/protocol/pjrc.mk
include $(TOP_DIR)/common.mk include $(TOP_DIR)/common.mk
include $(TOP_DIR)/protocol.mk
include $(TOP_DIR)/protocol/pjrc.mk
include $(TOP_DIR)/rules.mk include $(TOP_DIR)/rules.mk

plain: OPT_DEFS += -DKEYMAP_PLAIN
plain: all

poker: OPT_DEFS += -DKEYMAP_POKER
poker: all

poker_set: OPT_DEFS += -DKEYMAP_POKER_SET
poker_set: all

poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT
poker_bit: all

+ 86
- 0
keyboard/onekey/config.h View File

//#define NO_ACTION_MACRO //#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION //#define NO_ACTION_FUNCTION



/* PS/2 mouse */
#ifdef PS2_USE_BUSYWAIT
# define PS2_CLOCK_PORT PORTD
# define PS2_CLOCK_PIN PIND
# define PS2_CLOCK_DDR DDRD
# define PS2_CLOCK_BIT 5
# define PS2_DATA_PORT PORTD
# define PS2_DATA_PIN PIND
# define PS2_DATA_DDR DDRD
# define PS2_DATA_BIT 2
#endif


/* PS/2 mouse interrupt version */
#ifdef PS2_USE_INT
/* uses INT1 for clock line(ATMega32U4) */
#define PS2_CLOCK_PORT PORTD
#define PS2_CLOCK_PIN PIND
#define PS2_CLOCK_DDR DDRD
#define PS2_CLOCK_BIT 5
#define PS2_DATA_PORT PORTD
#define PS2_DATA_PIN PIND
#define PS2_DATA_DDR DDRD
#define PS2_DATA_BIT 2

#define PS2_INT_INIT() do { \
EICRA |= ((1<<ISC11) | \
(0<<ISC10)); \
} while (0)
#define PS2_INT_ON() do { \
EIMSK |= (1<<INT1); \
} while (0)
#define PS2_INT_OFF() do { \
EIMSK &= ~(1<<INT1); \
} while (0)
#define PS2_INT_VECT INT1_vect
#endif


/* PS/2 mouse USART version */
#ifdef PS2_USE_USART
#if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
/* XCK for clock line and RXD for data line */
#define PS2_CLOCK_PORT PORTD
#define PS2_CLOCK_PIN PIND
#define PS2_CLOCK_DDR DDRD
#define PS2_CLOCK_BIT 5
#define PS2_DATA_PORT PORTD
#define PS2_DATA_PIN PIND
#define PS2_DATA_DDR DDRD
#define PS2_DATA_BIT 2

/* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */
/* set DDR of CLOCK as input to be slave */
#define PS2_USART_INIT() do { \
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); \
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); \
UCSR1C = ((1 << UMSEL10) | \
(3 << UPM10) | \
(0 << USBS1) | \
(3 << UCSZ10) | \
(0 << UCPOL1)); \
UCSR1A = 0; \
UBRR1H = 0; \
UBRR1L = 0; \
} while (0)
#define PS2_USART_RX_INT_ON() do { \
UCSR1B = ((1 << RXCIE1) | \
(1 << RXEN1)); \
} while (0)
#define PS2_USART_RX_POLL_ON() do { \
UCSR1B = (1 << RXEN1); \
} while (0)
#define PS2_USART_OFF() do { \
UCSR1C = 0; \
UCSR1B &= ~((1 << RXEN1) | \
(1 << TXEN1)); \
} while (0)
#define PS2_USART_RX_READY (UCSR1A & (1<<RXC1))
#define PS2_USART_RX_DATA UDR1
#define PS2_USART_ERROR (UCSR1A & ((1<<FE1) | (1<<DOR1) | (1<<UPE1)))
#define PS2_USART_RX_VECT USART1_RX_vect
#endif
#endif

#endif #endif

+ 1
- 0
keyboard/onekey/matrix.c View File

{ {
debug_enable = true; debug_enable = true;
debug_matrix = true; debug_matrix = true;
debug_mouse = true;
// initialize row and col // initialize row and col
unselect_rows(); unselect_rows();
init_cols(); init_cols();

+ 25
- 0
protocol.mk View File

PROTOCOL_DIR = protocol


ifdef PS2_MOUSE_ENABLE
SRC += $(PROTOCOL_DIR)/ps2_mouse.c
OPT_DEFS += -DPS2_MOUSE_ENABLE
OPT_DEFS += -DMOUSE_ENABLE
endif

ifdef PS2_USE_BUSYWAIT
SRC += protocol/ps2.c
OPT_DEFS += -DPS2_USE_BUSYWAIT
endif

ifdef PS2_USE_INT
SRC += protocol/ps2.c
OPT_DEFS += -DPS2_USE_INT
endif

ifdef PS2_USE_USART
SRC += protocol/ps2_usart.c
OPT_DEFS += -DPS2_USE_USART
endif


# Search Path # Search Path
VPATH += $(TOP_DIR)/protocol VPATH += $(TOP_DIR)/protocol

+ 8
- 1
protocol/lufa/lufa.c View File

{ {
SetupHardware(); SetupHardware();
sei(); sei();

/* wait for USB startup & debug output */
while (USB_DeviceState != DEVICE_STATE_Configured) {
#if defined(INTERRUPT_CONTROL_ENDPOINT) #if defined(INTERRUPT_CONTROL_ENDPOINT)
while (USB_DeviceState != DEVICE_STATE_Configured) ;
;
#else
USB_USBTask();
#endif #endif
}
print("USB configured.\n"); print("USB configured.\n");


/* init modules */
keyboard_init(); keyboard_init();
host_set_driver(&lufa_driver); host_set_driver(&lufa_driver);
#ifdef SLEEP_LED_ENABLE #ifdef SLEEP_LED_ENABLE

+ 5
- 1
protocol/pjrc.mk View File

$(PJRC_DIR)/usb.c $(PJRC_DIR)/usb.c


# Option modules # 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 SRC += $(PJRC_DIR)/usb_mouse.c
endif endif



+ 38
- 21
protocol/ps2.c View File

/* /*
Copyright 2010,2011 Jun WAKO <[email protected]>
Copyright 2010,2011,2012,2013 Jun WAKO <[email protected]>


This software is licensed with a Modified BSD License. This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free, All of this is supposed to be Free Software, Open Source, DFSG-free,
#include "debug.h" #include "debug.h"




#ifndef PS2_USE_INT
static uint8_t recv_data(void); static uint8_t recv_data(void);
#endif
static inline void clock_lo(void); static inline void clock_lo(void);
static inline void clock_hi(void); static inline void clock_hi(void);
static inline bool clock_in(void); static inline bool clock_in(void);
#endif #endif
/* terminate a transmission if we have */ /* terminate a transmission if we have */
inhibit(); inhibit();
_delay_us(100);
_delay_us(200); // at least 100us


/* start bit [1] */ /* start bit [1] */
data_lo(); data_lo();
clock_hi(); clock_hi();
WAIT(clock_lo, 15000, 1);
WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking
/* data [2-9] */ /* data [2-9] */
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
_delay_us(15); _delay_us(15);
WAIT(clock_hi, 50, 8); WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9); WAIT(data_hi, 50, 9);


#ifdef PS2_USE_INT
PS2_INT_ON();
#endif
res = ps2_host_recv_response(); res = ps2_host_recv_response();
ERROR: ERROR:
#ifdef PS2_USE_INT #ifdef PS2_USE_INT
return res; return res;
} }


#ifndef PS2_USE_INT
/* receive data when host want else inhibit communication */ /* receive data when host want else inhibit communication */
uint8_t ps2_host_recv_response(void) uint8_t ps2_host_recv_response(void)
{ {
uint8_t data = 0; uint8_t data = 0;


#ifdef PS2_USE_INT
PS2_INT_OFF();
#endif
/* terminate a transmission if we have */ /* terminate a transmission if we have */
inhibit(); inhibit();
_delay_us(100); _delay_us(100);
idle(); idle();


/* wait start bit */ /* wait start bit */
wait_clock_lo(2000);
wait_clock_lo(25000); // command response may take 20 ms at most
data = recv_data(); data = recv_data();


inhibit(); inhibit();
return data; return data;
} }
#endif


#ifndef PS2_USE_INT #ifndef PS2_USE_INT
uint8_t ps2_host_recv(void) uint8_t ps2_host_recv(void)
static uint8_t pbuf_tail = 0; static uint8_t pbuf_tail = 0;
static inline void pbuf_enqueue(uint8_t data) static inline void pbuf_enqueue(uint8_t data)
{ {
if (!data)
return;

uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
uint8_t next = (pbuf_head + 1) % PBUF_SIZE; uint8_t next = (pbuf_head + 1) % PBUF_SIZE;


return val; return val;
} }
static inline bool pbuf_has_data(void)
{
uint8_t sreg = SREG;
cli();
bool has_data = (pbuf_head != pbuf_tail);
SREG = sreg;
return has_data;
}
static inline void pbuf_clear(void)
{
uint8_t sreg = SREG;
cli();
pbuf_head = pbuf_tail = 0;
SREG = sreg;
}


/* get data received by interrupt */ /* get data received by interrupt */
uint8_t ps2_host_recv(void) uint8_t ps2_host_recv(void)
return pbuf_dequeue(); 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
uint8_t ps2_host_recv_response(void)
{
while (!pbuf_has_data()) ;
return pbuf_dequeue();
}

ISR(PS2_INT_VECT) ISR(PS2_INT_VECT)
{ {
static enum { static enum {
} }


state++; state++;
DEBUGP(state);
switch (state) { switch (state) {
case START: case START:
if (data_in()) if (data_in())
if (!data_in()) if (!data_in())
goto ERROR; goto ERROR;
pbuf_enqueue(data); pbuf_enqueue(data);
//phex(data);
goto DONE; goto DONE;
break; break;
default: default:
} }
goto RETURN; goto RETURN;
ERROR: ERROR:
DEBUGP(0x0F);
inhibit(); inhibit();
ps2_error = state; ps2_error = state;
DONE: DONE:
#endif #endif




static void ps2_reset(void)
{
ps2_host_send(0xFF);
}

/* send LED state to keyboard */ /* send LED state to keyboard */
void ps2_host_set_led(uint8_t led) void ps2_host_set_led(uint8_t led)
{ {
} }




#ifndef PS2_USE_INT
/* called after start bit comes */ /* called after start bit comes */
static uint8_t recv_data(void) static uint8_t recv_data(void)
{ {
ERROR: ERROR:
return 0; return 0;
} }
#endif


static inline void clock_lo() static inline void clock_lo()
{ {

+ 150
- 153
protocol/ps2_mouse.c View File

/* /*
Copyright 2011 Jun Wako <[email protected]>
Copyright 2011,2013 Jun Wako <[email protected]>


This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
#include<util/delay.h> #include<util/delay.h>
#include "ps2.h" #include "ps2.h"
#include "ps2_mouse.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 ps2_mouse_init(void) {
uint8_t rcv; uint8_t rcv;


if (!ps2_mouse_enable) return 1;

ps2_host_init(); 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"); 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: "); print("ps2_mouse_init: read BAT: ");
phex(rcv); phex(ps2_error); print("\n"); 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: "); print("ps2_mouse_init: read DevID: ");
phex(rcv); phex(ps2_error); print("\n"); 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: "); 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"); phex(rcv); phex(ps2_error); print("\n");
ERROR_RETURN();


return 0; 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; 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;

// PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value.
// bit: 8 7 ... 0
// sign \8-bit/
//
// Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used.
//
// This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit.
mouse_report.x = X_IS_NEG ?
((!X_IS_OVF && -127 <= mouse_report.x && mouse_report.x <= -1) ? mouse_report.x : -127) :
((!X_IS_OVF && 0 <= mouse_report.x && mouse_report.x <= 127) ? mouse_report.x : 127);
mouse_report.y = Y_IS_NEG ?
((!Y_IS_OVF && -127 <= mouse_report.y && mouse_report.y <= -1) ? mouse_report.y : -127) :
((!Y_IS_OVF && 0 <= mouse_report.y && mouse_report.y <= 127) ? mouse_report.y : 127);

// remove sign and overflow flags
mouse_report.buttons &= PS2_MOUSE_BTN_MASK;

// invert coordinate of y to conform to USB HID mouse
mouse_report.y = -mouse_report.y;


#if PS2_MOUSE_SCROLL_BTN_MASK
static uint16_t scroll_button_time = 0;
if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == (PS2_MOUSE_SCROLL_BTN_MASK)) {
if (scroll_state == SCROLL_NONE) {
scroll_button_time = timer_read();
scroll_state = SCROLL_BTN;
}


if(rcv==0xFA) {
ps2_mouse_btn = ps2_host_recv();
ERROR_RETURN();
ps2_mouse_x = ps2_host_recv();
ERROR_RETURN();
ps2_mouse_y = ps2_host_recv();
ERROR_RETURN();
}
return 0;
}
// doesn't send Scroll Button
//mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK);


bool ps2_mouse_changed(void)
{
return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev);
}
if (mouse_report.x || mouse_report.y) {
scroll_state = SCROLL_SENT;


#define PS2_MOUSE_SCROLL_BUTTON 0x04
void ps2_mouse_usb_send(void)
{
static bool scrolled = false;

if (!ps2_mouse_enable) return;

if (ps2_mouse_changed()) {
int8_t x, y, v, h;
x = y = v = h = 0;

// convert scale of X, Y: PS/2(-256/255) -> USB(-127/127)
if (ps2_mouse_btn & (1<<PS2_MOUSE_X_SIGN))
x = ps2_mouse_x > 128 ? (int8_t)ps2_mouse_x : -127;
else
x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127;

if (ps2_mouse_btn & (1<<PS2_MOUSE_Y_SIGN))
y = ps2_mouse_y > 128 ? (int8_t)ps2_mouse_y : -127;
else
y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127;

// Y is needed to reverse
y = -y;

if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) {
// scroll
if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x));
if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y));
if (h || v) {
scrolled = true;
usb_mouse_send(0,0, -v/16, h/16, 0);
mouse_report.v = -mouse_report.y/(PS2_MOUSE_SCROLL_DIVISOR_V);
mouse_report.h = mouse_report.x/(PS2_MOUSE_SCROLL_DIVISOR_H);
mouse_report.x = 0;
mouse_report.y = 0;
//host_mouse_send(&mouse_report);
}
}
else if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == 0) {
#if PS2_MOUSE_SCROLL_BTN_SEND
if (scroll_state == SCROLL_BTN &&
TIMER_DIFF_16(timer_read(), scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) {
// send Scroll Button(down and up at once) when not scrolled
mouse_report.buttons |= (PS2_MOUSE_SCROLL_BTN_MASK);
host_mouse_send(&mouse_report);
_delay_ms(100); _delay_ms(100);
mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK);
} }
} else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) {
usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON);
_delay_ms(100);
usb_mouse_send(0,0,0,0, 0);
} else {
scrolled = false;
usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
#endif
scroll_state = SCROLL_NONE;
} }
// doesn't send Scroll Button
mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK);
#endif



ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
ps2_mouse_print();
host_mouse_send(&mouse_report);
print_usb_data();
} }
ps2_mouse_x = 0;
ps2_mouse_y = 0;
ps2_mouse_btn = 0;
// clear report
mouse_report.x = 0;
mouse_report.y = 0;
mouse_report.v = 0;
mouse_report.h = 0;
mouse_report.buttons = 0;
} }


void ps2_mouse_print(void)
static void print_usb_data(void)
{ {
if (!debug_mouse) return; if (!debug_mouse) return;
print("ps2_mouse[btn|x y]: ");
phex(ps2_mouse_btn); print("|");
phex(ps2_mouse_x); print(" ");
phex(ps2_mouse_y); print("\n");
print("ps2_mouse usb: [");
phex(mouse_report.buttons); print("|");
print_hex8((uint8_t)mouse_report.x); print(" ");
print_hex8((uint8_t)mouse_report.y); print(" ");
print_hex8((uint8_t)mouse_report.v); print(" ");
print_hex8((uint8_t)mouse_report.h); print("]\n");
} }


/* PS/2 Mouse Synopsis
* http://www.computer-engineering.org/ps2mouse/
*
* Command:
* 0xFF: Reset
* 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled
* 0xF5: Disable Data Reporting
* 0xF4: Enable Data Reporting
* 0xF3: Set Sample Rate
* 0xF2: Get Device ID
* 0xF0: Set Remote Mode
* 0xEB: Read Data
* 0xEA: Set Stream Mode
* 0xE9: Status Request
* 0xE8: Set Resolution
* 0xE7: Set Scaling 2:1
* 0xE6: Set Scaling 1:1
*
* Mode:
* Stream Mode: devices sends the data when it changs its state
* Remote Mode: host polls the data periodically
*
* This code uses Remote Mode and polls the data with Read Data(0xEB).
*
* Data format:
* byte|7 6 5 4 3 2 1 0
* ----+--------------------------------------------------------------
* 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left
* 1| X movement
* 2| Y movement
*/

+ 31
- 9
protocol/ps2_mouse.h View File



#include <stdbool.h> #include <stdbool.h>


#define PS2_MOUSE_READ_DATA 0xEB

/*
* Data format:
* byte|7 6 5 4 3 2 1 0
* ----+--------------------------------------------------------------
* 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left
* 1| X movement(0-255)
* 2| Y movement(0-255)
*/
#define PS2_MOUSE_BTN_MASK 0x07 #define PS2_MOUSE_BTN_MASK 0x07
#define PS2_MOUSE_BTN_LEFT 0 #define PS2_MOUSE_BTN_LEFT 0
#define PS2_MOUSE_BTN_RIGHT 1 #define PS2_MOUSE_BTN_RIGHT 1
#define PS2_MOUSE_X_OVFLW 6 #define PS2_MOUSE_X_OVFLW 6
#define PS2_MOUSE_Y_OVFLW 7 #define PS2_MOUSE_Y_OVFLW 7


bool ps2_mouse_enable;
extern uint8_t ps2_mouse_x;
extern uint8_t ps2_mouse_y;
extern uint8_t ps2_mouse_btn;
extern uint8_t ps2_mouse_error_count;

/*
* Scroll by mouse move with pressing button
*/
/* mouse button to start scrolling; set 0 to disable scroll */
#ifndef PS2_MOUSE_SCROLL_BTN_MASK
#define PS2_MOUSE_SCROLL_BTN_MASK (1<<PS2_MOUSE_BTN_MIDDLE)
#endif
/* send button event when button is released within this value(ms); set 0 to disable */
#ifndef PS2_MOUSE_SCROLL_BTN_SEND
#define PS2_MOUSE_SCROLL_BTN_SEND 300
#endif
/* divide virtical and horizontal mouse move by this to convert to scroll move */
#ifndef PS2_MOUSE_SCROLL_DIVISOR_V
#define PS2_MOUSE_SCROLL_DIVISOR_V 2
#endif
#ifndef PS2_MOUSE_SCROLL_DIVISOR_H
#define PS2_MOUSE_SCROLL_DIVISOR_H 2
#endif



uint8_t ps2_mouse_init(void); uint8_t ps2_mouse_init(void);
uint8_t ps2_mouse_read(void);
bool ps2_mouse_changed(void);
void ps2_mouse_usb_send(void);
void ps2_mouse_print(void);
void ps2_mouse_task(void);


#endif #endif

+ 25
- 29
protocol/ps2_usart.c View File

/* /*
Copyright 2010,2011 Jun WAKO <[email protected]>
Copyright 2010,2011,2012,2013 Jun WAKO <[email protected]>


This software is licensed with a Modified BSD License. This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free, All of this is supposed to be Free Software, Open Source, DFSG-free,
#include "debug.h" #include "debug.h"




#if 0
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
#define DEBUGP(x) do { PORTC = x; } while (0)
#else
#define DEBUGP_INIT()
#define DEBUGP(x)
#endif

#define WAIT(stat, us, err) do { \ #define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \ if (!wait_##stat(us)) { \
ps2_error = err; \ ps2_error = err; \
static inline void inhibit(void); static inline void inhibit(void);
static inline uint8_t pbuf_dequeue(void); static inline uint8_t pbuf_dequeue(void);
static inline void pbuf_enqueue(uint8_t data); 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) void ps2_host_init(void)
{ {
DEBUGP_INIT();
DEBUGP(0x1);
idle(); idle();
PS2_USART_INIT(); PS2_USART_INIT();
PS2_USART_RX_INT_ON(); PS2_USART_RX_INT_ON();
bool parity = true; bool parity = true;
ps2_error = PS2_ERR_NONE; ps2_error = PS2_ERR_NONE;


DEBUGP(0x6);
PS2_USART_OFF(); PS2_USART_OFF();


/* terminate a transmission if we have */ /* terminate a transmission if we have */
WAIT(clock_hi, 50, 8); WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9); WAIT(data_hi, 50, 9);


PS2_USART_INIT();
PS2_USART_RX_INT_ON();
res = ps2_host_recv_response(); res = ps2_host_recv_response();
ERROR: ERROR:
idle(); idle();
// Do polling data from keyboard to get response to last command. // Do polling data from keyboard to get response to last command.
uint8_t ps2_host_recv_response(void) uint8_t ps2_host_recv_response(void)
{ {
uint8_t data = 0;
PS2_USART_INIT();
PS2_USART_RX_POLL_ON();
while (!PS2_USART_RX_READY)
;
data = PS2_USART_RX_DATA;
PS2_USART_OFF();
DEBUGP(0x9);
return data;
while (!pbuf_has_data()) {
_delay_ms(1); // without this delay it seems to fall into deadlock
}
return pbuf_dequeue();
} }


uint8_t ps2_host_recv(void) uint8_t ps2_host_recv(void)


ISR(PS2_USART_RX_VECT) ISR(PS2_USART_RX_VECT)
{ {
DEBUGP(0x7);
uint8_t error = PS2_USART_ERROR; uint8_t error = PS2_USART_ERROR;
uint8_t data = PS2_USART_RX_DATA; uint8_t data = PS2_USART_RX_DATA;
if (error) {
DEBUGP(error>>2);
} else {
if (!error) {
pbuf_enqueue(data); pbuf_enqueue(data);
} }
DEBUGP(0x8);
} }


/* send LED state to keyboard */ /* send LED state to keyboard */
static uint8_t pbuf_tail = 0; static uint8_t pbuf_tail = 0;
static inline void pbuf_enqueue(uint8_t data) static inline void pbuf_enqueue(uint8_t data)
{ {
if (!data)
return;

uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
uint8_t next = (pbuf_head + 1) % PBUF_SIZE; uint8_t next = (pbuf_head + 1) % PBUF_SIZE;


return val; return val;
} }
static inline bool pbuf_has_data(void)
{
uint8_t sreg = SREG;
cli();
bool has_data = (pbuf_head != pbuf_tail);
SREG = sreg;
return has_data;
}
static inline void pbuf_clear(void)
{
uint8_t sreg = SREG;
cli();
pbuf_head = pbuf_tail = 0;
SREG = sreg;
}

Loading…
Cancel
Save