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 } |