2 Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
4 This software is licensed with a Modified BSD License.
5 All of this is supposed to be Free Software, Open Source, DFSG-free,
6 GPL-compatible, and OK to use in both free and proprietary applications.
7 Additions and corrections to this file are welcome.
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
21 * Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 POSSIBILITY OF SUCH DAMAGE.
40 #include <avr/interrupt.h>
41 #include <util/delay.h>
47 static uint8_t recv_data(void);
49 static inline void clock_lo(void);
50 static inline void clock_hi(void);
51 static inline bool clock_in(void);
52 static inline void data_lo(void);
53 static inline void data_hi(void);
54 static inline bool data_in(void);
55 static inline uint16_t wait_clock_lo(uint16_t us);
56 static inline uint16_t wait_clock_hi(uint16_t us);
57 static inline uint16_t wait_data_lo(uint16_t us);
58 static inline uint16_t wait_data_hi(uint16_t us);
59 static inline void idle(void);
60 static inline void inhibit(void);
64 Primitive PS/2 Library for AVR
65 ==============================
66 Host side is only supported now.
71 High state is asserted by input with pull up.
76 http://www.computer-engineering.org/ps2protocol/
77 http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
81 #define WAIT(stat, us, err) do { \
82 if (!wait_##stat(us)) { \
89 uint8_t ps2_error = PS2_ERR_NONE;
92 void ps2_host_init(void)
103 // TODO: send using interrupt if available
104 uint8_t ps2_host_send(uint8_t data)
108 ps2_error = PS2_ERR_NONE;
112 /* terminate a transmission if we have */
114 _delay_us(200); // at least 100us
119 WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking
121 for (uint8_t i = 0; i < 8; i++) {
129 WAIT(clock_hi, 50, 2);
130 WAIT(clock_lo, 50, 3);
134 if (parity) { data_hi(); } else { data_lo(); }
135 WAIT(clock_hi, 50, 4);
136 WAIT(clock_lo, 50, 5);
141 WAIT(data_lo, 50, 6);
142 WAIT(clock_lo, 50, 7);
144 /* wait for idle state */
145 WAIT(clock_hi, 50, 8);
146 WAIT(data_hi, 50, 9);
151 res = ps2_host_recv_response();
163 /* receive data when host want else inhibit communication */
164 uint8_t ps2_host_recv_response(void)
171 /* terminate a transmission if we have */
175 /* release lines(idle state) */
179 wait_clock_lo(25000); // command response may take 20 ms at most
188 uint8_t ps2_host_recv(void)
190 return ps2_host_recv_response();
193 /* ring buffer to store ps/2 key data */
195 static uint8_t pbuf[PBUF_SIZE];
196 static uint8_t pbuf_head = 0;
197 static uint8_t pbuf_tail = 0;
198 static inline void pbuf_enqueue(uint8_t data)
202 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
203 if (next != pbuf_tail) {
204 pbuf[pbuf_head] = data;
207 debug("pbuf: full\n");
211 static inline uint8_t pbuf_dequeue(void)
217 if (pbuf_head != pbuf_tail) {
218 val = pbuf[pbuf_tail];
219 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
225 static inline bool pbuf_has_data(void)
229 bool has_data = (pbuf_head != pbuf_tail);
233 static inline void pbuf_clear(void)
237 pbuf_head = pbuf_tail = 0;
241 /* get data received by interrupt */
242 uint8_t ps2_host_recv(void)
247 ps2_host_send(0xFE); // request to resend
248 ps2_error = PS2_ERR_NONE;
251 return pbuf_dequeue();
254 uint8_t ps2_host_recv_response(void)
256 while (!pbuf_has_data()) ;
257 return pbuf_dequeue();
265 BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7,
269 static uint8_t data = 0;
270 static uint8_t parity = 1;
272 // TODO: abort if elapse 100us from previous interrupt
274 // return unless falling edge
301 if (!(parity & 0x01))
332 /* send LED state to keyboard */
333 void ps2_host_set_led(uint8_t led)
341 /* called after start bit comes */
342 static uint8_t recv_data(void)
346 ps2_error = PS2_ERR_NONE;
349 WAIT(clock_lo, 1, 1);
351 WAIT(clock_hi, 50, 3);
354 for (uint8_t i = 0; i < 8; i++) {
355 WAIT(clock_lo, 50, 4);
360 WAIT(clock_hi, 50, 5);
364 WAIT(clock_lo, 50, 6);
365 if (data_in() != parity) {
366 ps2_error = PS2_ERR_PARITY;
369 WAIT(clock_hi, 50, 7);
372 WAIT(clock_lo, 50, 8);
374 WAIT(clock_hi, 50, 10);
382 static inline void clock_lo()
384 PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
385 PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
387 static inline void clock_hi()
389 /* input with pull up */
390 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
391 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
393 static inline bool clock_in()
395 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
396 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
398 return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
400 static inline void data_lo()
402 PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
403 PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
405 static inline void data_hi()
407 /* input with pull up */
408 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
409 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
411 static inline bool data_in()
413 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
414 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
416 return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
419 static inline uint16_t wait_clock_lo(uint16_t us)
421 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
424 static inline uint16_t wait_clock_hi(uint16_t us)
426 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
429 static inline uint16_t wait_data_lo(uint16_t us)
431 while (data_in() && us) { asm(""); _delay_us(1); us--; }
434 static inline uint16_t wait_data_hi(uint16_t us)
436 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
440 /* idle state that device can send */
441 static inline void idle(void)
447 /* inhibit device to send */
448 static inline void inhibit(void)