a500kbd

annotate src/ps2kbd.c @ 3:31a1f0b53d98

- scroll lock now acts as caps lock - the scroll-lock light indicates drive activity
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 18 Oct 2017 08:20:58 +0300
parents a4fd9c5a6655
children
rev   line source
nuclear@2 1 #include <avr/io.h>
nuclear@2 2 #include <avr/interrupt.h>
nuclear@2 3 #include <util/delay.h>
nuclear@2 4 #include "ps2kbd.h"
nuclear@2 5 #include "defs.h"
nuclear@3 6 #include "timer.h"
nuclear@3 7
nuclear@3 8 #define TIMEOUT 100
nuclear@2 9
nuclear@2 10 #define BUF_SZ 16
nuclear@2 11 #define BUF_IDX_MASK (BUF_SZ - 1)
nuclear@2 12 #define NEXT_IDX(x) (((x) + 1) & BUF_IDX_MASK)
nuclear@2 13 static volatile unsigned char keybuf[BUF_SZ];
nuclear@2 14 static volatile unsigned char key_rd, key_wr;
nuclear@2 15
nuclear@3 16 static volatile int send_nbits, wait_ack;
nuclear@3 17 static volatile unsigned char send_val, send_par;
nuclear@2 18
nuclear@3 19 static void abort_send(void);
nuclear@3 20
nuclear@3 21 int ps2write(unsigned char c)
nuclear@2 22 {
nuclear@3 23 cli();
nuclear@3 24 send_nbits = 10;
nuclear@3 25 send_val = c;
nuclear@3 26 send_par = 0; /* init to 0, will be calculated while sending */
nuclear@2 27
nuclear@3 28 /* inhibit transmission, hold at least 100us */
nuclear@3 29 PORTD &= ~PCLK_BIT;
nuclear@3 30 DDRD |= PCLK_BIT;
nuclear@3 31 EIFR |= (1 << INTF0); /* clear pending interrupt due to clock transition */
nuclear@3 32 sei();
nuclear@3 33 _delay_us(100);
nuclear@2 34
nuclear@3 35 /* RTS by data low & release clock (this counts as start bit?) */
nuclear@3 36 PORTD &= ~PDATA_BIT;
nuclear@3 37 DDRD |= PDATA_BIT;
nuclear@3 38 DDRD &= ~PCLK_BIT;
nuclear@2 39
nuclear@3 40 reset_timer();
nuclear@3 41 while(send_nbits > 0) {
nuclear@3 42 if(get_msec() > TIMEOUT) {
nuclear@3 43 abort_send();
nuclear@3 44 return -1;
nuclear@3 45 }
nuclear@2 46 }
nuclear@3 47 _delay_us(5);
nuclear@2 48
nuclear@3 49 /* release data line and wait for ack */
nuclear@3 50 cli();
nuclear@3 51 wait_ack = 1;
nuclear@3 52 sei();
nuclear@3 53 DDRD &= ~PDATA_BIT;
nuclear@3 54 reset_timer();
nuclear@3 55 while(wait_ack) {
nuclear@3 56 if(get_msec() > TIMEOUT) {
nuclear@3 57 abort_send();
nuclear@3 58 return -1;
nuclear@3 59 }
nuclear@3 60 }
nuclear@3 61 return 0;
nuclear@3 62 }
nuclear@3 63
nuclear@3 64 static void abort_send(void)
nuclear@3 65 {
nuclear@3 66 cli();
nuclear@3 67 send_nbits = 0;
nuclear@3 68 wait_ack = 0;
nuclear@3 69 /* hold clock low for 100us */
nuclear@3 70 PORTD &= ~PCLK_BIT;
nuclear@3 71 DDRD |= PCLK_BIT;
nuclear@3 72 _delay_us(100);
nuclear@3 73 DDRD &= ~(PCLK_BIT | PDATA_BIT);
nuclear@3 74 EIFR |= (1 << INTF0); /* clear pending interrupt */
nuclear@3 75 sei();
nuclear@2 76 }
nuclear@2 77
nuclear@2 78 unsigned char ps2read(void)
nuclear@2 79 {
nuclear@2 80 unsigned char key;
nuclear@2 81
nuclear@2 82 while(key_rd == key_wr) {
nuclear@2 83 }
nuclear@2 84
nuclear@2 85 cli();
nuclear@2 86 key = keybuf[key_rd];
nuclear@2 87 key_rd = NEXT_IDX(key_rd);
nuclear@2 88 sei();
nuclear@2 89
nuclear@2 90 return key;
nuclear@2 91 }
nuclear@2 92
nuclear@2 93 int ps2pending(void)
nuclear@2 94 {
nuclear@2 95 return key_rd != key_wr;
nuclear@2 96 }
nuclear@2 97
nuclear@3 98 int ps2wait(unsigned int timeout)
nuclear@3 99 {
nuclear@3 100 reset_timer();
nuclear@3 101 while(key_rd == key_wr) {
nuclear@3 102 if(get_msec() >= timeout) return -1;
nuclear@3 103 }
nuclear@3 104 return 0;
nuclear@3 105 }
nuclear@3 106
nuclear@3 107 #define PS2_ACK 0xfa
nuclear@3 108 #define PS2_RESEND 0xfe
nuclear@3 109 #define PS2_ECHO 0xee
nuclear@3 110
nuclear@3 111 int ps2setled(unsigned char state)
nuclear@3 112 {
nuclear@3 113 unsigned char c;
nuclear@3 114
nuclear@3 115 ps2write(0xed);
nuclear@3 116 reset_timer();
nuclear@3 117 while(!ps2pending()) {
nuclear@3 118 if(get_msec() >= TIMEOUT) return -1;
nuclear@3 119 }
nuclear@3 120 c = ps2read();
nuclear@3 121 /*printf("ps2setled 1st response: %x\r\n", (unsigned int)c);*/
nuclear@3 122 if(c != PS2_ACK) return -1;
nuclear@3 123
nuclear@3 124 ps2write(state);
nuclear@3 125 reset_timer();
nuclear@3 126 while(!ps2pending()) {
nuclear@3 127 if(get_msec() >= TIMEOUT) return -1;
nuclear@3 128 }
nuclear@3 129 c = ps2read();
nuclear@3 130 /*printf("ps2setled 2nd response: %x\r\n", (unsigned int)c);*/
nuclear@3 131 if(c != PS2_ACK) return -1;
nuclear@3 132
nuclear@3 133 return 0;
nuclear@3 134 }
nuclear@3 135
nuclear@2 136 ISR(INT0_vect)
nuclear@2 137 {
nuclear@2 138 static unsigned char value, parity;
nuclear@2 139 /*static unsigned char valp;*/
nuclear@2 140 static int nbits;
nuclear@2 141
nuclear@3 142 if(wait_ack) {
nuclear@3 143 if(!(PIND & PDATA_BIT)) {
nuclear@3 144 wait_ack = 0;
nuclear@3 145 }
nuclear@3 146 return;
nuclear@3 147 }
nuclear@3 148
nuclear@3 149 if(send_nbits > 0) {
nuclear@3 150 --send_nbits;
nuclear@3 151 switch(send_nbits) {
nuclear@3 152 case 1: /* parity bit */
nuclear@3 153 if(send_par & 1) { /* odd number of ones: parity 0 */
nuclear@3 154 PORTD &= ~PDATA_BIT;
nuclear@3 155 } else { /* even number of ones: parity 1 */
nuclear@3 156 PORTD |= PDATA_BIT;
nuclear@3 157 }
nuclear@3 158 break;
nuclear@3 159 case 0: /* stop bit: 1 */
nuclear@3 160 PORTD |= PDATA_BIT;
nuclear@3 161 break;
nuclear@3 162 default:
nuclear@3 163 if(send_val & 1) {
nuclear@3 164 PORTD |= PDATA_BIT;
nuclear@3 165 ++send_par;
nuclear@3 166 } else {
nuclear@3 167 PORTD &= ~PDATA_BIT;
nuclear@3 168 }
nuclear@3 169 send_val >>= 1;
nuclear@3 170 }
nuclear@3 171
nuclear@2 172 } else {
nuclear@2 173 if(nbits > 0 && nbits < 9) {
nuclear@2 174 value >>= 1;
nuclear@2 175 if(PIND & PDATA_BIT) {
nuclear@2 176 value |= 0x80;
nuclear@2 177 parity ^= 1;
nuclear@2 178 }
nuclear@2 179 }/* else if(nbits == 9) {
nuclear@2 180 valp = (PIND >> PDATA) & 1;
nuclear@2 181 }*/
nuclear@2 182 if(++nbits >= 11) {
nuclear@2 183 nbits = 0;
nuclear@2 184
nuclear@2 185 /* check parity */
nuclear@2 186 /*if((parity & 1) == (valp & 1)) {}*/
nuclear@2 187 keybuf[key_wr] = (unsigned char)value;
nuclear@2 188 key_wr = NEXT_IDX(key_wr);
nuclear@2 189
nuclear@2 190 value = 0;
nuclear@2 191 parity = 0;
nuclear@2 192 }
nuclear@2 193 }
nuclear@2 194 }