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