forked from mirrors/qmk_userspace
		
	Add ps2_usart.c and fix set_led at USB wake
This commit is contained in:
		
					parent
					
						
							
								9d26053f1c
							
						
					
				
			
			
				commit
				
					
						532e100450
					
				
			
		
					 4 changed files with 29 additions and 126 deletions
				
			
		| 
						 | 
					@ -148,7 +148,6 @@ static void Console_Task(void)
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void EVENT_USB_Device_Connect(void)
 | 
					void EVENT_USB_Device_Connect(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    led_set(0x1f);  // all on
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EVENT_USB_Device_Disconnect(void)
 | 
					void EVENT_USB_Device_Disconnect(void)
 | 
				
			||||||
| 
						 | 
					@ -172,8 +171,9 @@ void EVENT_USB_Device_WakeUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SLEEP_LED_ENABLE
 | 
					#ifdef SLEEP_LED_ENABLE
 | 
				
			||||||
    sleep_led_disable();
 | 
					    sleep_led_disable();
 | 
				
			||||||
#endif
 | 
					    // NOTE: converters may not accept this
 | 
				
			||||||
    led_set(host_keyboard_leds());
 | 
					    led_set(host_keyboard_leds());
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EVENT_USB_Device_StartOfFrame(void)
 | 
					void EVENT_USB_Device_StartOfFrame(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -662,8 +662,9 @@ ISR(USB_GEN_vect)
 | 
				
			||||||
            suspend_wakeup_init();
 | 
					            suspend_wakeup_init();
 | 
				
			||||||
#ifdef SLEEP_LED_ENABLE
 | 
					#ifdef SLEEP_LED_ENABLE
 | 
				
			||||||
            sleep_led_disable();
 | 
					            sleep_led_disable();
 | 
				
			||||||
#endif
 | 
					            // NOTE: converters may not accept this
 | 
				
			||||||
            led_set(host_keyboard_leds());
 | 
					            led_set(host_keyboard_leds());
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            UDIEN |= (1<<SUSPE);
 | 
					            UDIEN |= (1<<SUSPE);
 | 
				
			||||||
            UDIEN &= ~(1<<WAKEUPE);
 | 
					            UDIEN &= ~(1<<WAKEUPE);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,11 +70,13 @@ POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
#define PS2_RESEND      0xFE
 | 
					#define PS2_RESEND      0xFE
 | 
				
			||||||
#define PS2_SET_LED     0xED
 | 
					#define PS2_SET_LED     0xED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: error numbers
 | 
				
			||||||
#define PS2_ERR_NONE        0
 | 
					#define PS2_ERR_NONE        0
 | 
				
			||||||
#define PS2_ERR_STARTBIT1   1
 | 
					#define PS2_ERR_STARTBIT1   1
 | 
				
			||||||
#define PS2_ERR_STARTBIT2   2
 | 
					#define PS2_ERR_STARTBIT2   2
 | 
				
			||||||
#define PS2_ERR_STARTBIT3   3
 | 
					#define PS2_ERR_STARTBIT3   3
 | 
				
			||||||
#define PS2_ERR_PARITY      0x10
 | 
					#define PS2_ERR_PARITY      0x10
 | 
				
			||||||
 | 
					#define PS2_ERR_NODATA      0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PS2_LED_SCROLL_LOCK 0
 | 
					#define PS2_LED_SCROLL_LOCK 0
 | 
				
			||||||
#define PS2_LED_NUM_LOCK    1
 | 
					#define PS2_LED_NUM_LOCK    1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,26 +36,9 @@ POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Primitive PS/2 Library for AVR
 | 
					 * PS/2 protocol USART version
 | 
				
			||||||
==============================
 | 
					 */
 | 
				
			||||||
Host side is only supported now.
 | 
					 | 
				
			||||||
Synchronous USART is used to receive data by hardware process
 | 
					 | 
				
			||||||
rather than interrupt. During V-USB interrupt runs, CLOCK interrupt
 | 
					 | 
				
			||||||
cannot interpose. In the result it is prone to lost CLOCK edge.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
I/O control
 | 
					 | 
				
			||||||
-----------
 | 
					 | 
				
			||||||
High state is asserted by internal pull-up.
 | 
					 | 
				
			||||||
If you have a signaling problem, you may need to have
 | 
					 | 
				
			||||||
external pull-up resisters on CLOCK and DATA line.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PS/2 References
 | 
					 | 
				
			||||||
---------------
 | 
					 | 
				
			||||||
http://www.computer-engineering.org/ps2protocol/
 | 
					 | 
				
			||||||
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <avr/io.h>
 | 
					#include <avr/io.h>
 | 
				
			||||||
#include <avr/interrupt.h>
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
| 
						 | 
					@ -75,18 +58,6 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
 | 
				
			||||||
uint8_t ps2_error = PS2_ERR_NONE;
 | 
					uint8_t ps2_error = PS2_ERR_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
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 bool pbuf_has_data(void);
 | 
				
			||||||
| 
						 | 
					@ -95,14 +66,15 @@ static inline void pbuf_clear(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ps2_host_init(void)
 | 
					void ps2_host_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    idle();
 | 
					    idle(); // without this many USART errors occur when cable is disconnected
 | 
				
			||||||
    PS2_USART_INIT();
 | 
					    PS2_USART_INIT();
 | 
				
			||||||
    PS2_USART_RX_INT_ON();
 | 
					    PS2_USART_RX_INT_ON();
 | 
				
			||||||
 | 
					    // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
 | 
				
			||||||
 | 
					    //_delay_ms(2500);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t ps2_host_send(uint8_t data)
 | 
					uint8_t ps2_host_send(uint8_t data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t res = 0;
 | 
					 | 
				
			||||||
    bool parity = true;
 | 
					    bool parity = true;
 | 
				
			||||||
    ps2_error = PS2_ERR_NONE;
 | 
					    ps2_error = PS2_ERR_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,20 +116,22 @@ uint8_t ps2_host_send(uint8_t data)
 | 
				
			||||||
    WAIT(clock_hi, 50, 8);
 | 
					    WAIT(clock_hi, 50, 8);
 | 
				
			||||||
    WAIT(data_hi, 50, 9);
 | 
					    WAIT(data_hi, 50, 9);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    idle();
 | 
				
			||||||
    PS2_USART_INIT();
 | 
					    PS2_USART_INIT();
 | 
				
			||||||
    PS2_USART_RX_INT_ON();
 | 
					    PS2_USART_RX_INT_ON();
 | 
				
			||||||
    res = ps2_host_recv_response();
 | 
					    return ps2_host_recv_response();
 | 
				
			||||||
ERROR:
 | 
					ERROR:
 | 
				
			||||||
    idle();
 | 
					    idle();
 | 
				
			||||||
    PS2_USART_INIT();
 | 
					    PS2_USART_INIT();
 | 
				
			||||||
    PS2_USART_RX_INT_ON();
 | 
					    PS2_USART_RX_INT_ON();
 | 
				
			||||||
    return res;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    while (!pbuf_has_data()) {
 | 
					    uint8_t retry = 25;
 | 
				
			||||||
 | 
					    while (retry-- && !pbuf_has_data()) {
 | 
				
			||||||
        _delay_ms(1);   // without this delay it seems to fall into deadlock
 | 
					        _delay_ms(1);   // without this delay it seems to fall into deadlock
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return pbuf_dequeue();
 | 
					    return pbuf_dequeue();
 | 
				
			||||||
| 
						 | 
					@ -165,106 +139,32 @@ uint8_t ps2_host_recv_response(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t ps2_host_recv(void)
 | 
					uint8_t ps2_host_recv(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return pbuf_dequeue();
 | 
					    if (pbuf_has_data()) {
 | 
				
			||||||
 | 
					        ps2_error = PS2_ERR_NONE;
 | 
				
			||||||
 | 
					        return pbuf_dequeue();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ps2_error = PS2_ERR_NODATA;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ISR(PS2_USART_RX_VECT)
 | 
					ISR(PS2_USART_RX_VECT)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t error = PS2_USART_ERROR;
 | 
					    // TODO: request RESEND when error occurs?
 | 
				
			||||||
 | 
					    uint8_t error = PS2_USART_ERROR;    // USART error should be read before data
 | 
				
			||||||
    uint8_t data = PS2_USART_RX_DATA;
 | 
					    uint8_t data = PS2_USART_RX_DATA;
 | 
				
			||||||
    if (!error) {
 | 
					    if (!error) {
 | 
				
			||||||
        pbuf_enqueue(data);
 | 
					        pbuf_enqueue(data);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        xprintf("PS2 USART error: %02X data: %02X\n", error, data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // send 0xED then keyboard keeps waiting for next LED data
 | 
					    ps2_host_send(0xED);
 | 
				
			||||||
    // and keyboard does not send any scan codes during waiting.
 | 
					    ps2_host_send(led);
 | 
				
			||||||
    // If fail to send LED data keyboard looks like being freezed.
 | 
					 | 
				
			||||||
    uint8_t retry = 3;
 | 
					 | 
				
			||||||
    while (retry-- && ps2_host_send(PS2_SET_LED) != PS2_ACK)
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    retry = 3;
 | 
					 | 
				
			||||||
    while (retry-- && ps2_host_send(led) != PS2_ACK)
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*--------------------------------------------------------------------
 | 
					 | 
				
			||||||
 * static functions
 | 
					 | 
				
			||||||
 *------------------------------------------------------------------*/
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static inline bool data_in()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue