a500kbd

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