qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

ps2_busywait.c (4844B)


      1 /*
      2 Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
      3 
      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.
      8 
      9 
     10 Redistribution and use in source and binary forms, with or without
     11 modification, are permitted provided that the following conditions are met:
     12 
     13 * Redistributions of source code must retain the above copyright
     14   notice, this list of conditions and the following disclaimer.
     15 
     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
     19   distribution.
     20 
     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.
     24 
     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.
     36 */
     37 
     38 /*
     39  * PS/2 protocol busywait version
     40  */
     41 
     42 #include <stdbool.h>
     43 #include "wait.h"
     44 #include "ps2.h"
     45 #include "ps2_io.h"
     46 #include "debug.h"
     47 
     48 #define WAIT(stat, us, err)     \
     49     do {                        \
     50         if (!wait_##stat(us)) { \
     51             ps2_error = err;    \
     52             goto ERROR;         \
     53         }                       \
     54     } while (0)
     55 
     56 uint8_t ps2_error = PS2_ERR_NONE;
     57 
     58 void ps2_host_init(void) {
     59     clock_init();
     60     data_init();
     61 
     62     // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
     63     wait_ms(2500);
     64 
     65     inhibit();
     66 }
     67 
     68 uint8_t ps2_host_send(uint8_t data) {
     69     bool parity = true;
     70     ps2_error   = PS2_ERR_NONE;
     71 
     72     /* terminate a transmission if we have */
     73     inhibit();
     74     wait_us(100); // 100us [4]p.13, [5]p.50
     75 
     76     /* 'Request to Send' and Start bit */
     77     data_lo();
     78     clock_hi();
     79     WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
     80 
     81     /* Data bit */
     82     for (uint8_t i = 0; i < 8; i++) {
     83         wait_us(15);
     84         if (data & (1 << i)) {
     85             parity = !parity;
     86             data_hi();
     87         } else {
     88             data_lo();
     89         }
     90         WAIT(clock_hi, 50, 2);
     91         WAIT(clock_lo, 50, 3);
     92     }
     93 
     94     /* Parity bit */
     95     wait_us(15);
     96     if (parity) {
     97         data_hi();
     98     } else {
     99         data_lo();
    100     }
    101     WAIT(clock_hi, 50, 4);
    102     WAIT(clock_lo, 50, 5);
    103 
    104     /* Stop bit */
    105     wait_us(15);
    106     data_hi();
    107 
    108     /* Ack */
    109     WAIT(data_lo, 50, 6);
    110     WAIT(clock_lo, 50, 7);
    111 
    112     /* wait for idle state */
    113     WAIT(clock_hi, 50, 8);
    114     WAIT(data_hi, 50, 9);
    115 
    116     inhibit();
    117     return ps2_host_recv_response();
    118 ERROR:
    119     inhibit();
    120     return 0;
    121 }
    122 
    123 /* receive data when host want else inhibit communication */
    124 uint8_t ps2_host_recv_response(void) {
    125     // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
    126     // 250 * 100us(wait for start bit in ps2_host_recv)
    127     uint8_t data = 0;
    128     uint8_t try  = 250;
    129     do {
    130         data = ps2_host_recv();
    131     } while (try-- && ps2_error);
    132     return data;
    133 }
    134 
    135 /* called after start bit comes */
    136 uint8_t ps2_host_recv(void) {
    137     uint8_t data   = 0;
    138     bool    parity = true;
    139     ps2_error      = PS2_ERR_NONE;
    140 
    141     /* release lines(idle state) */
    142     idle();
    143 
    144     /* start bit [1] */
    145     WAIT(clock_lo, 100, 1); // TODO: this is enough?
    146     WAIT(data_lo, 1, 2);
    147     WAIT(clock_hi, 50, 3);
    148 
    149     /* data [2-9] */
    150     for (uint8_t i = 0; i < 8; i++) {
    151         WAIT(clock_lo, 50, 4);
    152         if (data_in()) {
    153             parity = !parity;
    154             data |= (1 << i);
    155         }
    156         WAIT(clock_hi, 50, 5);
    157     }
    158 
    159     /* parity [10] */
    160     WAIT(clock_lo, 50, 6);
    161     if (data_in() != parity) {
    162         ps2_error = PS2_ERR_PARITY;
    163         goto ERROR;
    164     }
    165     WAIT(clock_hi, 50, 7);
    166 
    167     /* stop bit [11] */
    168     WAIT(clock_lo, 50, 8);
    169     WAIT(data_hi, 1, 9);
    170     WAIT(clock_hi, 50, 10);
    171 
    172     inhibit();
    173     return data;
    174 ERROR:
    175     if (ps2_error > PS2_ERR_STARTBIT3) {
    176         xprintf("x%02X\n", ps2_error);
    177     }
    178     inhibit();
    179     return 0;
    180 }
    181 
    182 /* send LED state to keyboard */
    183 void ps2_host_set_led(uint8_t led) {
    184     ps2_host_send(0xED);
    185     ps2_host_send(led);
    186 }