/* | /* | ||||
Copyright (c) 2010 Jun WAKO <[email protected]> | |||||
Copyright (c) 2010,2011 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 <stdbool.h> | #include <stdbool.h> | ||||
#include <avr/io.h> | #include <avr/io.h> | ||||
#include <avr/interrupt.h> | |||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#include "ps2.h" | #include "ps2.h" | ||||
#include "print.h" | |||||
#include "debug.h" | #include "debug.h" | ||||
static uint8_t recv_data(void); | |||||
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); | ||||
static inline uint16_t wait_clock_hi(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_lo(uint16_t us); | ||||
static inline uint16_t wait_data_hi(uint16_t us); | static inline uint16_t wait_data_hi(uint16_t us); | ||||
static inline void idle(void); | |||||
static inline void inhibit(void); | |||||
/* | /* | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
#define WAIT_NORETRY(stat, us, err) do { \ | |||||
if (!wait_##stat(us)) { \ | |||||
ps2_error = err; \ | |||||
return 0; \ | |||||
} \ | |||||
} while (0) | |||||
uint8_t ps2_error = PS2_ERR_NONE; | uint8_t ps2_error = PS2_ERR_NONE; | ||||
void ps2_host_init(void) | void ps2_host_init(void) | ||||
{ | { | ||||
/* inhibit */ | |||||
clock_lo(); | |||||
data_hi(); | |||||
#ifdef PS2_INT_ENABLE | |||||
PS2_INT_ENABLE(); | |||||
idle(); | |||||
#else | |||||
inhibit(); | |||||
#endif | |||||
} | } | ||||
uint8_t ps2_host_send(uint8_t data) | uint8_t ps2_host_send(uint8_t data) | ||||
{ | { | ||||
bool parity = true; | |||||
bool parity; | |||||
RETRY: | |||||
parity = true; | |||||
ps2_error = 0; | ps2_error = 0; | ||||
/* request to send */ | |||||
clock_lo(); | |||||
/* terminate a transmission if we have */ | |||||
inhibit(); | |||||
_delay_us(100); | _delay_us(100); | ||||
/* start bit [1] */ | /* start bit [1] */ | ||||
data_lo(); | data_lo(); | ||||
clock_hi(); | clock_hi(); | ||||
WAIT(clock_lo, 15000, 1); | WAIT(clock_lo, 15000, 1); | ||||
/* 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); | |||||
if (data&(1<<i)) { | if (data&(1<<i)) { | ||||
parity = !parity; | parity = !parity; | ||||
data_hi(); | data_hi(); | ||||
WAIT(clock_lo, 50, 3); | WAIT(clock_lo, 50, 3); | ||||
} | } | ||||
/* parity [10] */ | /* parity [10] */ | ||||
_delay_us(15); | |||||
if (parity) { data_hi(); } else { data_lo(); } | if (parity) { data_hi(); } else { data_lo(); } | ||||
WAIT(clock_hi, 50, 4); | WAIT(clock_hi, 50, 4); | ||||
WAIT(clock_lo, 50, 5); | WAIT(clock_lo, 50, 5); | ||||
/* stop bit [11] */ | /* stop bit [11] */ | ||||
_delay_us(15); | |||||
data_hi(); | data_hi(); | ||||
/* ack [12] */ | /* ack [12] */ | ||||
WAIT(data_lo, 50, 6); | WAIT(data_lo, 50, 6); | ||||
WAIT(clock_lo, 50, 7); | WAIT(clock_lo, 50, 7); | ||||
/* wait for idle state */ | |||||
WAIT(clock_hi, 50, 8); | WAIT(clock_hi, 50, 8); | ||||
WAIT(data_hi, 50, 9); | WAIT(data_hi, 50, 9); | ||||
/* inhibit device to send */ | |||||
clock_lo(); | |||||
uint8_t res = ps2_host_recv_response(); | |||||
if (res == 0xFE && data != 0xFE) | |||||
goto RETRY; | |||||
return 1; | |||||
inhibit(); | |||||
return res; | |||||
ERROR: | ERROR: | ||||
/* inhibit device to send */ | |||||
data_hi(); | |||||
clock_lo(); | |||||
inhibit(); | |||||
return 0; | return 0; | ||||
} | } | ||||
uint8_t ps2_host_recv(void) | |||||
/* receive data when host want else inhibit communication */ | |||||
uint8_t ps2_host_recv_response(void) | |||||
{ | { | ||||
uint8_t data = 0; | uint8_t data = 0; | ||||
bool parity = true; | |||||
ps2_error = 0; | |||||
/* terminate a transmission if we have */ | /* terminate a transmission if we have */ | ||||
clock_lo(); | |||||
inhibit(); | |||||
_delay_us(100); | _delay_us(100); | ||||
/* release lines(idle state) */ | /* release lines(idle state) */ | ||||
clock_hi(); | |||||
data_hi(); | |||||
idle(); | |||||
/* wait start bit */ | |||||
wait_clock_lo(2000); | |||||
data = recv_data(); | |||||
inhibit(); | |||||
return data; | |||||
} | |||||
#ifndef PS2_INT_VECT | |||||
uint8_t ps2_host_recv(void) | |||||
{ | |||||
return ps2_host_recv_response(); | |||||
} | |||||
#else | |||||
/* ring buffer to store ps/2 key data */ | |||||
#define PBUF_SIZE 8 | |||||
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 next = (pbuf_head + 1) % PBUF_SIZE; | |||||
if (next != pbuf_tail) { | |||||
pbuf[pbuf_head] = data; | |||||
pbuf_head = next; | |||||
} else { | |||||
print("pbuf: full\n"); | |||||
} | |||||
} | |||||
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; | |||||
} | |||||
SREG = sreg; | |||||
return val; | |||||
} | |||||
/* get data received by interrupt */ | |||||
uint8_t ps2_host_recv(void) | |||||
{ | |||||
return pbuf_dequeue(); | |||||
} | |||||
ISR(PS2_INT_VECT) | |||||
{ | |||||
PORTC = 0xFF; | |||||
/* interrupt means start bit comes */ | |||||
pbuf_enqueue(recv_data()); | |||||
/* release lines(idle state) */ | |||||
idle(); | |||||
_delay_us(5); | |||||
PORTC = 0x00; | |||||
} | |||||
#endif | |||||
/* | |||||
static void ps2_reset(void) | |||||
{ | |||||
ps2_host_send(0xFF); | |||||
if (ps2_host_recv_response() == 0xFA) { | |||||
_delay_ms(1000); | |||||
ps2_host_recv_response(); | |||||
} | |||||
} | |||||
*/ | |||||
/* send LED state to keyboard */ | |||||
void ps2_host_set_led(uint8_t led) | |||||
{ | |||||
#ifdef PS2_INT_DISABLE | |||||
PS2_INT_DISABLE(); | |||||
#endif | |||||
ps2_host_send(0xED); | |||||
ps2_host_recv_response(); | |||||
ps2_host_send(led); | |||||
ps2_host_recv_response(); | |||||
#ifdef PS2_INT_ENABLE | |||||
PS2_INT_ENABLE(); | |||||
idle(); | |||||
#endif | |||||
} | |||||
/* called after start bit comes */ | |||||
static uint8_t recv_data(void) | |||||
{ | |||||
uint8_t data = 0; | |||||
bool parity = true; | |||||
ps2_error = 0; | |||||
/* start bit [1] */ | /* start bit [1] */ | ||||
WAIT(clock_lo, 2000, 1); // How long should we wait? | |||||
WAIT(clock_lo, 1, 1); | |||||
WAIT(data_lo, 1, 2); | WAIT(data_lo, 1, 2); | ||||
WAIT(clock_hi, 50, 3); | WAIT(clock_hi, 50, 3); | ||||
WAIT(data_hi, 1, 9); | WAIT(data_hi, 1, 9); | ||||
WAIT(clock_hi, 50, 10); | WAIT(clock_hi, 50, 10); | ||||
/* inhibit device to send */ | |||||
clock_lo(); | |||||
return data; | return data; | ||||
ERROR: | ERROR: | ||||
/* inhibit device to send */ | |||||
data_hi(); | |||||
clock_lo(); | |||||
return 0; | return 0; | ||||
} | } | ||||
static inline void clock_lo() | static inline void clock_lo() | ||||
{ | { | ||||
PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT); | PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT); | ||||
while (!data_in() && us) { asm(""); _delay_us(1); us--; } | while (!data_in() && us) { asm(""); _delay_us(1); us--; } | ||||
return 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(); | |||||
} |
/* | /* | ||||
Copyright (c) 2010 Jun WAKO <[email protected]> | |||||
Copyright (c) 2010,2011 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, | ||||
extern uint8_t ps2_error; | extern uint8_t ps2_error; | ||||
/* host side */ | |||||
/* host role */ | |||||
void ps2_host_init(void); | void ps2_host_init(void); | ||||
uint8_t ps2_host_send(uint8_t); | |||||
uint8_t ps2_host_send(uint8_t data); | |||||
uint8_t ps2_host_recv_response(void); | |||||
uint8_t ps2_host_recv(void); | uint8_t ps2_host_recv(void); | ||||
void ps2_host_set_led(uint8_t usb_led); | |||||
/* TODO: device side */ | |||||
/* device role */ | |||||
#endif | #endif |
# define MOUSEKEY_DELAY_TIME 255 | # define MOUSEKEY_DELAY_TIME 255 | ||||
#endif | #endif | ||||
/* PS/2 mouse */ | |||||
/* PS/2 lines */ | |||||
#define PS2_CLOCK_PORT PORTD | #define PS2_CLOCK_PORT PORTD | ||||
#define PS2_CLOCK_PIN PIND | #define PS2_CLOCK_PIN PIND | ||||
#define PS2_CLOCK_DDR DDRD | #define PS2_CLOCK_DDR DDRD | ||||
#define PS2_CLOCK_BIT 6 | |||||
#define PS2_CLOCK_BIT 3 | |||||
#define PS2_DATA_PORT PORTD | #define PS2_DATA_PORT PORTD | ||||
#define PS2_DATA_PIN PIND | #define PS2_DATA_PIN PIND | ||||
#define PS2_DATA_DDR DDRD | #define PS2_DATA_DDR DDRD | ||||
#define PS2_DATA_BIT 7 | #define PS2_DATA_BIT 7 | ||||
/* External interrupt for PS/2 clock line (optional) */ | |||||
#define PS2_INT_ENABLE() do { \ | |||||
EIMSK |= (1<<INT1); \ | |||||
EICRA |= ((1<<ISC11) | (0<<ISC10)); \ | |||||
EIFR |= (1<<INTF1); \ | |||||
} while (0) | |||||
#define PS2_INT_DISABLE() do { \ | |||||
EIMSK &= ~(1<<INT1); \ | |||||
} while (0) | |||||
#define PS2_INT_VECT INT1_vect | |||||
/* Pin Change interrupt for PS/2 clock line (optional) | |||||
#define PS2_INT_ENABLE() do { \ | |||||
PCMSK2 |= (1<<PCINT22); \ | |||||
PCICR |= (1<<PCIE2); \ | |||||
PCIFR |= (1<<PCIF2); \ | |||||
} while (0) | |||||
#define PS2_INT_DISABLE() do { \ | |||||
PCMSK2 &= ~(1<<PCINT22); \ | |||||
PCICR &= ~(1<<PCIE); \ | |||||
} while (0) | |||||
#define PS2_INT_VECT PCINT2_vect | |||||
*/ | |||||
#endif | #endif |
} report_mouse_t; | } report_mouse_t; | ||||
extern uint8_t host_keyboard_led; | |||||
void host_keyboard_send(report_keyboard_t *report); | void host_keyboard_send(report_keyboard_t *report); | ||||
void host_mouse_send(report_mouse_t *report); | void host_mouse_send(report_mouse_t *report); | ||||
#include "host_vusb.h" | #include "host_vusb.h" | ||||
#define KBUF_SIZE 8 | |||||
#define KBUF_SIZE 16 | |||||
static report_keyboard_t kbuf[KBUF_SIZE]; | static report_keyboard_t kbuf[KBUF_SIZE]; | ||||
static uint8_t kbuf_head = 0; | static uint8_t kbuf_head = 0; | ||||
static uint8_t kbuf_tail = 0; | static uint8_t kbuf_tail = 0; | ||||
void host_vusb_keyboard_send() | void host_vusb_keyboard_send() | ||||
{ | { | ||||
while (usbInterruptIsReady() && kbuf_head != kbuf_tail) { | |||||
usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | |||||
kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | |||||
} | |||||
/* | |||||
if (kbuf_head != kbuf_tail) { | if (kbuf_head != kbuf_tail) { | ||||
if (usbInterruptIsReady()) { | if (usbInterruptIsReady()) { | ||||
usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | ||||
kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | ||||
} | } | ||||
} | } | ||||
*/ | |||||
} | } | ||||
void host_keyboard_send(report_keyboard_t *report) | void host_keyboard_send(report_keyboard_t *report) | ||||
if (next != kbuf_tail) { | if (next != kbuf_tail) { | ||||
kbuf[kbuf_head] = *report; | kbuf[kbuf_head] = *report; | ||||
kbuf_head = next; | kbuf_head = next; | ||||
print("kbuf: "); phex(kbuf_head); phex(kbuf_tail); print("\n"); | |||||
} else { | |||||
print("kbuf: full\n"); | |||||
// hmm... | |||||
/* | |||||
matrix_init(); | |||||
kbuf_head = 0; | |||||
kbuf_tail = 0; | |||||
*/ | |||||
} | } | ||||
} | } | ||||
void host_mouse_send(report_mouse_t *report) | void host_mouse_send(report_mouse_t *report) | ||||
{ | { | ||||
// dirty hack to send twice a loop :( | |||||
//while (!usbInterruptIsReady3()) usbPoll(); | |||||
if (usbInterruptIsReady3()) { | if (usbInterruptIsReady3()) { | ||||
usbSetInterrupt3((void *)report, sizeof(*report)); | usbSetInterrupt3((void *)report, sizeof(*report)); | ||||
} else { | } else { | ||||
static struct { | |||||
uint16_t len; | |||||
enum { | |||||
NONE, | |||||
SET_LED | |||||
} kind; | |||||
} last_req; | |||||
uint8_t host_keyboard_led = 0; | |||||
static uchar idleRate; | |||||
static uchar idleRate; /* repeat rate for keyboards, never used for mice */ | |||||
usbMsgLen_t usbFunctionSetup(uchar data[8]) | usbMsgLen_t usbFunctionSetup(uchar data[8]) | ||||
{ | { | ||||
usbRequest_t *rq = (void *)data; | usbRequest_t *rq = (void *)data; | ||||
print("Setup: "); | |||||
//print("Setup: "); | |||||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | ||||
/* | |||||
print("CLASS: "); | print("CLASS: "); | ||||
phex(rq->bRequest); | |||||
phex(rq->bRequest); print(" "); | |||||
phex16(rq->wValue.word); print(" "); | |||||
phex16(rq->wIndex.word); print(" "); | |||||
phex16(rq->wLength.word); print(" "); | |||||
*/ | |||||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ | if(rq->bRequest == USBRQ_HID_GET_REPORT){ | ||||
print("GET_REPORT"); | |||||
print(" GET_REPORT"); | |||||
/* we only have one report type, so don't look at wValue */ | /* we only have one report type, so don't look at wValue */ | ||||
usbMsgPtr = (void *)keyboard_report; | usbMsgPtr = (void *)keyboard_report; | ||||
return sizeof(*keyboard_report); | return sizeof(*keyboard_report); | ||||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | ||||
print("GET_IDLE: "); | |||||
print(" GET_IDLE: "); | |||||
phex(idleRate); | phex(idleRate); | ||||
usbMsgPtr = &idleRate; | usbMsgPtr = &idleRate; | ||||
return 1; | return 1; | ||||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | ||||
idleRate = rq->wValue.bytes[1]; | idleRate = rq->wValue.bytes[1]; | ||||
print("SET_IDLE: "); | |||||
print(" SET_IDLE: "); | |||||
phex(idleRate); | phex(idleRate); | ||||
}else if(rq->bRequest == USBRQ_HID_SET_REPORT){ | |||||
//print(" SET_REPORT: "); | |||||
if (rq->wValue.word == 0x0200 && rq->wIndex.word == 0) { | |||||
last_req.kind = SET_LED; | |||||
last_req.len = rq->wLength.word; | |||||
} | |||||
return USB_NO_MSG; // to get data in usbFunctionWrite | |||||
} | } | ||||
print("\n"); | print("\n"); | ||||
}else{ | }else{ | ||||
return 0; /* default for not implemented requests: return no data back to host */ | return 0; /* default for not implemented requests: return no data back to host */ | ||||
} | } | ||||
uchar usbFunctionWrite(uchar *data, uchar len) | |||||
{ | |||||
if (last_req.len == 0) { | |||||
return -1; | |||||
} | |||||
switch (last_req.kind) { | |||||
case SET_LED: | |||||
//print("SET_LED\n"); | |||||
host_keyboard_led = data[0]; | |||||
last_req.len = 0; | |||||
return 1; | |||||
break; | |||||
case NONE: | |||||
default: | |||||
return -1; | |||||
break; | |||||
} | |||||
return 1; | |||||
} | |||||
PROGMEM uchar keyboard_hid_report[] = { | PROGMEM uchar keyboard_hid_report[] = { | ||||
0x05, 0x01, // Usage Page (Generic Desktop), | 0x05, 0x01, // Usage Page (Generic Desktop), |
void host_vusb_keyboard_send(void); | void host_vusb_keyboard_send(void); | ||||
#endif | #endif | ||||
#include "usb_keycodes.h" | #include "usb_keycodes.h" | ||||
#include "host.h" | #include "host.h" | ||||
#include "ps2.h" | |||||
#include "usb.h" | |||||
#include "keyboard.h" | #include "keyboard.h" | ||||
#include "print.h" | |||||
static report_keyboard_t report0; | static report_keyboard_t report0; | ||||
static report_keyboard_t report1; | static report_keyboard_t report1; | ||||
static report_keyboard_t *report = &report0; | static report_keyboard_t *report = &report0; | ||||
static report_keyboard_t *report_prev = &report1; | static report_keyboard_t *report_prev = &report1; | ||||
void keyboard_set_led(uint8_t usb_led) | |||||
{ | |||||
uint8_t ps2_led = 0; | |||||
if (usb_led & (1<<USB_LED_SCROLL_LOCK)) | |||||
ps2_led |= (1<<PS2_LED_SCROLL_LOCK); | |||||
if (usb_led & (1<<USB_LED_NUM_LOCK)) | |||||
ps2_led |= (1<<PS2_LED_NUM_LOCK); | |||||
if (usb_led & (1<<USB_LED_CAPS_LOCK)) | |||||
ps2_led |= (1<<PS2_LED_CAPS_LOCK); | |||||
print("ps2_led: "); phex(ps2_led); print("\n"); | |||||
ps2_host_set_led(ps2_led); | |||||
} | |||||
void keyboard_send(void) | void keyboard_send(void) | ||||
{ | { | ||||
host_keyboard_send(report); | host_keyboard_send(report); |
#include "host.h" | #include "host.h" | ||||
void keyboard_set_led(uint8_t led); | |||||
void keyboard_send(void); | void keyboard_send(void); | ||||
bool keyboard_has_key(void); | bool keyboard_has_key(void); | ||||
void keyboard_add_mod(uint8_t mod); | void keyboard_add_mod(uint8_t mod); |
#include "host_vusb.h" | #include "host_vusb.h" | ||||
#include "timer.h" | #include "timer.h" | ||||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||||
static uint8_t last_led = 0; | |||||
int main(void) | int main(void) | ||||
{ | { | ||||
DEBUGP_INIT(); | |||||
wdt_enable(WDTO_1S); | wdt_enable(WDTO_1S); | ||||
/* Even if you don't use the watchdog, turn it off here. On newer devices, | /* Even if you don't use the watchdog, turn it off here. On newer devices, | ||||
* the status of the watchdog (on/off, period) is PRESERVED OVER RESET! | * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! | ||||
uint8_t fn_bits = 0; | uint8_t fn_bits = 0; | ||||
while (1) { /* main event loop */ | while (1) { /* main event loop */ | ||||
DEBUGP(0x01); | |||||
wdt_reset(); | wdt_reset(); | ||||
usbPoll(); | usbPoll(); | ||||
host_vusb_keyboard_send(); | host_vusb_keyboard_send(); | ||||
DEBUGP(0x02); | |||||
matrix_scan(); | matrix_scan(); | ||||
fn_bits = 0; | fn_bits = 0; | ||||
keyboard_swap_report(); | keyboard_swap_report(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
DEBUGP(0x03); | |||||
layer_switching(fn_bits); | layer_switching(fn_bits); | ||||
if (matrix_is_modified()) { | if (matrix_is_modified()) { | ||||
keyboard_send(); | keyboard_send(); | ||||
} | } | ||||
mousekey_send(); | mousekey_send(); | ||||
if (last_led != host_keyboard_led) { | |||||
keyboard_set_led(host_keyboard_led); | |||||
last_led = host_keyboard_led; | |||||
} | |||||
} | } | ||||
} | } |
#endif | #endif | ||||
static void matrix_make(uint8_t code); | static void matrix_make(uint8_t code); | ||||
static void matrix_break(uint8_t code); | static void matrix_break(uint8_t code); | ||||
static void ps2_reset(void); | |||||
static void ps2_set_leds(uint8_t leds); | |||||
inline | inline | ||||
void matrix_init(void) | void matrix_init(void) | ||||
{ | { | ||||
ps2_host_init(); | ps2_host_init(); | ||||
_delay_ms(1000); | |||||
// flush LEDs | |||||
/* | |||||
ps2_set_leds(1<<PS2_LED_NUM_LOCK); | |||||
_delay_ms(100); | |||||
ps2_set_leds(1<<PS2_LED_NUM_LOCK|1<<PS2_LED_CAPS_LOCK); | |||||
_delay_ms(100); | |||||
ps2_set_leds(1<<PS2_LED_NUM_LOCK|1<<PS2_LED_CAPS_LOCK|1<<PS2_LED_SCROLL_LOCK); | |||||
_delay_ms(300); | |||||
ps2_set_leds(0x00); | |||||
*/ | |||||
// initialize matrix state: all keys off | // initialize matrix state: all keys off | ||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | ||||
} | } | ||||
uint8_t code; | uint8_t code; | ||||
code = ps2_host_recv(); | |||||
if (code == 0x00) return 0; | |||||
//while ((code = ps2_host_recv())) { | |||||
//phex(code); print(" "); | |||||
while ((code = ps2_host_recv())) { | |||||
switch (state) { | switch (state) { | ||||
case INIT: | case INIT: | ||||
switch (code) { | switch (code) { | ||||
default: | default: | ||||
state = INIT; | state = INIT; | ||||
} | } | ||||
//} | |||||
//print("|"); | |||||
// handle LED indicators | |||||
/* | |||||
static uint8_t prev_leds = 0; | |||||
if (prev_leds != usb_keyboard_leds) { | |||||
uint8_t leds = 0; | |||||
if (usb_keyboard_leds&(1<<USB_LED_SCROLL_LOCK)) | |||||
leds |= (1<<PS2_LED_SCROLL_LOCK); | |||||
if (usb_keyboard_leds&(1<<USB_LED_NUM_LOCK)) | |||||
leds |= (1<<PS2_LED_NUM_LOCK); | |||||
if (usb_keyboard_leds&(1<<USB_LED_CAPS_LOCK)) | |||||
leds |= (1<<PS2_LED_CAPS_LOCK); | |||||
ps2_set_leds(leds); | |||||
prev_leds = usb_keyboard_leds; | |||||
} | } | ||||
*/ | |||||
return 1; | return 1; | ||||
} | } | ||||
//print("matrix_break: "); phex(code); print("\n"); | //print("matrix_break: "); phex(code); print("\n"); | ||||
} | } | ||||
} | } | ||||
static void ps2_reset(void) | |||||
{ | |||||
ps2_host_send(0xFF); | |||||
if (ps2_host_recv() != 0xFA) return; | |||||
_delay_ms(1000); | |||||
if (ps2_host_recv() != 0xAA) return; | |||||
} | |||||
static void ps2_set_leds(uint8_t leds) | |||||
{ | |||||
ps2_host_send(0xED); | |||||
if (ps2_host_recv() != 0xFA) return; // 0xFA | |||||
ps2_host_send(leds); | |||||
if (ps2_host_recv() != 0xFA) return; // 0xFA | |||||
} |
* The value is in milliamperes. [It will be divided by two since USB | * The value is in milliamperes. [It will be divided by two since USB | ||||
* communicates power requirements in units of 2 mA.] | * communicates power requirements in units of 2 mA.] | ||||
*/ | */ | ||||
#define USB_CFG_IMPLEMENT_FN_WRITE 0 | |||||
#define USB_CFG_IMPLEMENT_FN_WRITE 1 | |||||
/* Set this to 1 if you want usbFunctionWrite() to be called for control-out | /* Set this to 1 if you want usbFunctionWrite() to be called for control-out | ||||
* transfers. Set it to 0 if you don't need it and want to save a couple of | * transfers. Set it to 0 if you don't need it and want to save a couple of | ||||
* bytes. | * bytes. |