a500kbd

annotate src/amigakb.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 <stdio.h>
nuclear@2 2 #include <avr/io.h>
nuclear@2 3 #include <avr/interrupt.h>
nuclear@2 4 #include <util/delay.h>
nuclear@2 5 #include "amigakb.h"
nuclear@2 6 #include "defs.h"
nuclear@2 7 #include "timer.h"
nuclear@2 8
nuclear@2 9 #define TIMEOUT_MSEC 143
nuclear@2 10
nuclear@2 11 static void resync(void);
nuclear@2 12
nuclear@2 13 void amikb_sendkey(unsigned char keycode, int press)
nuclear@2 14 {
nuclear@2 15 int i;
nuclear@2 16 static unsigned char prev_keycode = 0xff;
nuclear@3 17 static unsigned char capslk;
nuclear@3 18
nuclear@3 19 if(keycode == 0x62) {
nuclear@3 20 /* caps lock doesn't get a key release event when the key is released
nuclear@3 21 * but rather when the caps lock is toggled off again
nuclear@3 22 */
nuclear@3 23 if(!press) return;
nuclear@3 24
nuclear@3 25 capslk = ~capslk;
nuclear@3 26 press = capslk;
nuclear@3 27 }
nuclear@2 28
nuclear@2 29 /* keycode bit transfer order: 6 5 4 3 2 1 0 7 (7 is pressed flag) */
nuclear@2 30 keycode = (keycode << 1) | (~press & 1);
nuclear@2 31 if(keycode == prev_keycode) return;
nuclear@2 32 prev_keycode = keycode;
nuclear@2 33
nuclear@2 34 /* make sure we don't pulse the lines while grabbing control
nuclear@2 35 * by first reinstating the pullups before changing direction
nuclear@2 36 */
nuclear@2 37 PORTD |= ACLK_BIT | ADATA_BIT;
nuclear@2 38 DDRD |= ACLK_BIT | ADATA_BIT;
nuclear@2 39
nuclear@2 40 /* pulse the data line and wait for about 100us */
nuclear@2 41 PORTD &= ~ADATA_BIT;
nuclear@2 42 _delay_us(20);
nuclear@2 43 PORTD |= ADATA_BIT;
nuclear@2 44 _delay_us(100);
nuclear@2 45
nuclear@2 46 for(i=0; i<8; i++) {
nuclear@2 47 /* data line is inverted */
nuclear@2 48 if(keycode & 0x80) {
nuclear@2 49 PORTD &= ~ADATA_BIT;
nuclear@2 50 } else {
nuclear@2 51 PORTD |= ADATA_BIT;
nuclear@2 52 }
nuclear@2 53 keycode <<= 1;
nuclear@2 54 _delay_us(20);
nuclear@2 55 /* pulse the clock */
nuclear@2 56 cli();
nuclear@2 57 PORTD &= ~ACLK_BIT;
nuclear@2 58 EIFR |= (1 << INTF1);
nuclear@2 59 sei();
nuclear@2 60 _delay_us(20);
nuclear@2 61 PORTD |= ACLK_BIT;
nuclear@2 62 _delay_us(20);
nuclear@2 63 }
nuclear@2 64
nuclear@2 65 /* similarly tristate first, then drop the pullups */
nuclear@2 66 DDRD &= ~(ACLK_BIT | ADATA_BIT);
nuclear@2 67 PORTD &= ~(ACLK_BIT | ADATA_BIT);
nuclear@2 68
nuclear@2 69 /* wait for ack */
nuclear@2 70 reset_timer();
nuclear@2 71 while(PIND & ADATA_BIT) {
nuclear@2 72 if(get_msec() >= TIMEOUT_MSEC) {
nuclear@2 73 resync();
nuclear@2 74 break;
nuclear@2 75 }
nuclear@2 76 }
nuclear@2 77 }
nuclear@2 78
nuclear@2 79 void amikb_reset(void)
nuclear@2 80 {
nuclear@2 81 cli();
nuclear@2 82 PORTD &= ~ARST_BIT;
nuclear@2 83 DDRD |= ARST_BIT;
nuclear@2 84 _delay_ms(10);
nuclear@2 85 PORTD |= ARST_BIT;
nuclear@2 86 DDRD &= ~ARST_BIT;
nuclear@2 87 sei();
nuclear@2 88 }
nuclear@2 89
nuclear@2 90 static void resync(void)
nuclear@2 91 {
nuclear@2 92 PORTD |= ACLK_BIT | ADATA_BIT;
nuclear@2 93 printf("lost sync\r\n");
nuclear@2 94
nuclear@2 95 for(;;) {
nuclear@2 96 cli();
nuclear@2 97 DDRD |= ACLK_BIT | ADATA_BIT;
nuclear@2 98
nuclear@2 99 PORTD &= ~ACLK_BIT;
nuclear@2 100 EIFR |= (1 << INTF1); /* clear interrupt raised by the previous line */
nuclear@2 101 sei();
nuclear@2 102 _delay_us(20);
nuclear@2 103 PORTD |= ACLK_BIT;
nuclear@2 104
nuclear@2 105 DDRD &= ~(ACLK_BIT | ADATA_BIT);
nuclear@2 106
nuclear@2 107 reset_timer();
nuclear@2 108 while(get_msec() < TIMEOUT_MSEC) {
nuclear@2 109 if(!(PIND & ADATA_BIT)) {
nuclear@2 110 return;
nuclear@2 111 }
nuclear@2 112 }
nuclear@2 113 }
nuclear@2 114 }
nuclear@2 115
nuclear@2 116 static void handle_cmd(unsigned char cmd)
nuclear@2 117 {
nuclear@2 118 printf("amikbd got cmd: %x\r\n", (unsigned int)cmd);
nuclear@2 119 }
nuclear@2 120
nuclear@2 121 ISR(INT1_vect)
nuclear@2 122 {
nuclear@2 123 static unsigned char value;
nuclear@2 124 static int nbits;
nuclear@2 125
nuclear@2 126 value <<= 1;
nuclear@2 127 if(PIND & ADATA_BIT) {
nuclear@2 128 value |= 1;
nuclear@2 129 }
nuclear@2 130 if(++nbits >= 8) {
nuclear@2 131 handle_cmd(value);
nuclear@2 132 nbits = 0;
nuclear@2 133 value = 0;
nuclear@2 134 }
nuclear@2 135 }