Root/source/trendtac-gpio.ccp

Source at commit 12bfb32 created 13 years 10 months ago.
By Bas Wijnen, make things work with unfinished new startup procedure
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/gpio.ccp: GPIO driver, controlling all devices without special hardware.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "devices.hh"
20#define ARCH
21#include "arch.hh"
22
23// Interval between polls for keyboard events (when keys are pressed)
24#define ALARM_INTERVAL (HZ / 50)
25
26// GPIO pins for the devices (port.pin)
27
28// keyboard
29// Cols = 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.29
30// Rows = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7
31// For some reason, it only works if the rows are input and the columns are output.
32// interrupts: yes, with all columns set to output 0, the first key press can be detected as an interrupt; some other events also trigger interrupts.
33
34// touchpad buttons
35// Left: 0.16
36// Right: 0.13
37// interrupts: yes, for any change.
38
39// Lock leds
40// Num lock: 2.22
41// Caps lock: 0.27
42// Scroll lock: 0.9
43// interrupts: no, output only.
44
45// interrupt summary
46// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
47// Port 1: None.
48// Port 2: None.
49// Port 3: None.
50
51enum event_type:
52    KEYBOARD_EVENT
53    TOUCHPAD_EVENT
54    NUM_EVENTS
55
56static Iris::Cap events[NUM_EVENTS]
57
58static void event (event_type type, unsigned data):
59    events[type].invoke (data)
60
61static void set_cb (event_type type):
62    Iris::free_cap (events[type])
63    events[type] = Iris::get_arg ()
64
65class DevKeyboard:
66    static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
67    unsigned keys[GPIO_KBD_NUM_COLS]
68    bool scanning
69    void parse (unsigned col, unsigned data):
70        for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
71            if (data ^ keys[col]) & (1 << row):
72                unsigned code = encode[col][row]
73                if data & (1 << row):
74                    code |= Keyboard::RELEASE
75                event (KEYBOARD_EVENT, code)
76        keys[col] = data
77        // If any keys are pressed, scanning is required.
78        if data != GPIO_KBD_ROW_MASK:
79            scanning = true
80    public:
81    bool is_scanning ():
82        return scanning
83    void scan ():
84        // Disable interrupts during scan.
85        GPIO_GPIER (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
86        // All columns are input.
87        GPIO_GPDIR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
88        int const cols[GPIO_KBD_NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
89        unsigned dir = GPIO_GPDIR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
90        unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
91        // Set scanning to false before first parse.
92        scanning = false
93        // Clear all pins. This is only required once, because it's done at the end of the loop as well.
94        GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
95        for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
96            // Set pin to output.
97            GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
98            // Delay for stabalization.
99            for unsigned i = 0; i < 100; ++i:
100                GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
101            // Read the result.
102            unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
103            // Generate events.
104            parse (col, data)
105            // Set pin to get rid of capacitance effects.
106            GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
107            // Delay to make the above trick work.
108            for unsigned i = 0; i < 100; ++i:
109                GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
110            // Pin is set to input at the start of the loop.
111        // set all to 0.
112        GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
113        // set all to output.
114        GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
115        // Delay for stabalization.
116        for unsigned i = 0; i < 100; ++i:
117            GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
118        // Set interrupts.
119        unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
120        for unsigned i = 0; i < 8; ++i:
121            if data & (1 << i):
122                gpio_irq_low (GPIO_KBD_ROW_PORT, i)
123            else:
124                gpio_irq_high (GPIO_KBD_ROW_PORT, i)
125        // Reenable interrupts.
126        GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
127    DevKeyboard ():
128        // Set all columns to output without pull-ups when set as input.
129        GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
130        GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
131
132        // Set all rows to input and enable the pull-ups.
133        GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
134        GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
135        // Initialize things in the same way as when a new callback is set up.
136        send_initial ()
137    void send_initial ():
138        for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
139            keys[col] = 0xff
140        scan ()
141
142enum Keys:
143    N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
144    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
145    F1, F2, F3, F4, F5, F6, F7, F8, F9, F10
146    SPACE, TAB, ENTER, LBRACE, RBRACE, COMMA, PERIOD, MINUS, EQUAL, SLASH, BACKSLASH, SEMICOLON, EXTRA, BACKQUOTE, QUOTE
147    UP, DOWN, LEFT, RIGHT
148    ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
149    LSHIFT, RSHIFT, CTRL, ALT
150    CAPS, NUM
151    NONE = ~Keyboard::RELEASE
152
153unsigned const DevKeyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
154    { PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
155    { Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
156    { W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
157    { E, F3, D, F4, C, NONE, NONE, N3 },
158    { R, T, F, G, V, B, N5, N4 },
159    { U, Y, J, H, M, N, N6, N7 },
160    { I, RBRACE, K, F6, COMMA, NONE, EQUAL, N8 },
161    { O, F7, L, NONE, PERIOD, MENU, F8, N9 },
162    { NONE, NONE, NONE, SPACE, NUM, NONE, DELETE, NONE },
163    { NONE, BACKSPACE, NONE, NONE, ENTER, NONE, F9, NONE },
164    { NONE, NONE, NONE, ALT, NONE, NONE, NONE, SYSRQ },
165    { P, LBRACE, SEMICOLON, QUOTE, BACKSLASH, SLASH, MINUS, N0 },
166    { NONE, ZZZ, NONE, NONE, NONE, NONE, NONE, F10 },
167    { NONE, NONE, NONE, NONE, NONE, NONE, F2, NONE },
168    { NONE, NONE, NONE, NONE, NONE, NONE, INSERT, NONE },
169    { NONE, NONE, UP, DOWN, LEFT, RIGHT, NONE, NONE },
170    { NONE, LSHIFT, RSHIFT, NONE, NONE, NONE, F1, FN }}
171
172class Touchpad:
173    unsigned old_state
174    public:
175    void check_events ():
176        unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
177        if state & (1 << GPIO_TP_LEFT):
178            gpio_irq_low (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
179            if (state ^ old_state) & (1 << GPIO_TP_LEFT):
180                event (TOUCHPAD_EVENT, 0)
181        else:
182            gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
183            if (state ^ old_state) & (1 << GPIO_TP_LEFT):
184                event (TOUCHPAD_EVENT, 0 | Keyboard::RELEASE)
185        if state & (1 << GPIO_TP_RIGHT):
186            gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
187            if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
188                event (TOUCHPAD_EVENT, 1)
189        else:
190            gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
191            if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
192                event (TOUCHPAD_EVENT, 1 | Keyboard::RELEASE)
193        old_state = state
194        // Ack interrupts.
195        //GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
196    Touchpad ():
197        // Set pins to input with pull-ups.
198        gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
199        gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
200        GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
201        // See if they are already pressed. Also set up interrupts. This is done like when a new callback is registered.
202        send_initial ()
203    void send_initial ():
204        old_state = 0
205        check_events ()
206
207class Lockleds:
208    // Note that num lock is in port 2. The others are in port 0.
209    public:
210    Lockleds ():
211        gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
212        gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
213        gpio_as_output (GPIO_SCROLL_PORT, GPIO_SCROLL)
214        GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
215        GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
216        GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
217    void set (unsigned state):
218        if state & 4:
219            GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
220        else:
221            GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
222        if state & 2:
223            GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
224        else:
225            GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
226        if state & 1:
227            GPIO_GPDR (GPIO_SCROLL_PORT) &= ~(1 << GPIO_SCROLL)
228        else:
229            GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
230
231// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
232class Pwm:
233    public:
234    Pwm ():
235        GPIO_GPDIR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
236        PWM_PER (0) = 300
237    void set_backlight (unsigned level):
238        if level > 300:
239            level = 300
240        PWM_DUT (0) = level
241        if level:
242            PWM_CTR (0) = 0x80
243            GPIO_GPDR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
244        else:
245            PWM_CTR (0) = 0x00
246            GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
247    // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
248
249enum codes:
250    KEYBOARD = 32
251    TOUCHPAD
252    LOCKLEDS
253    PWM
254
255Iris::Num start ():
256    map_gpio ()
257    map_pwm0 ()
258
259    for unsigned i = 0; i < NUM_EVENTS; ++i:
260        events[i] = Iris::alloc_cap ()
261
262    DevKeyboard kbd
263    Touchpad tp
264    Lockleds leds
265    Pwm pwm
266
267    Iris::Cap c = Iris::my_receiver.create_capability (KEYBOARD)
268    Iris::my_parent.provide_device <Keyboard> (c.copy (), 0)
269    Iris::free_cap (c)
270    c = Iris::my_receiver.create_capability (TOUCHPAD)
271    Iris::my_parent.provide_device <Keyboard> (c.copy (), 1)
272    Iris::free_cap (c)
273    Iris::my_parent.init_done ()
274
275    if kbd.is_scanning ():
276        Iris::my_receiver.set_alarm (ALARM_INTERVAL)
277
278    // Enable interrupts. All are in port 0.
279    GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
280    Iris::register_interrupt (IRQ_GPIO0)
281
282    while true:
283        Iris::schedule ()
284        Iris::wait ()
285        switch Iris::recv.protected_data.l:
286            case ~0:
287                // Alarm.
288                kbd.scan ()
289                if kbd.is_scanning ():
290                    Iris::my_receiver.set_alarm (ALARM_INTERVAL)
291                break
292            case IRQ_GPIO0:
293                // Always scan keyboard and touchpad on any interrupt.
294                kbd.scan ()
295                tp.check_events ()
296                // Reregister the interrupt.
297                Iris::register_interrupt (IRQ_GPIO0)
298                break
299            case KEYBOARD:
300                set_cb (KEYBOARD_EVENT)
301                Iris::recv.reply.invoke ()
302                kbd.send_initial ()
303                event (KEYBOARD_EVENT, ~0)
304                break
305            case TOUCHPAD:
306                set_cb (TOUCHPAD_EVENT)
307                Iris::recv.reply.invoke ()
308                tp.send_initial ()
309                event (TOUCHPAD_EVENT, ~0)
310                break
311            case LOCKLEDS:
312                leds.set (Iris::recv.data[0].l)
313                Iris::recv.reply.invoke ()
314                break
315            case PWM:
316                pwm.set_backlight (Iris::recv.data[0].l)
317                Iris::recv.reply.invoke ()
318                break
319            default:
320                kdebug ("invalid gpio operation ")
321                kdebug_num (Iris::recv.protected_data.l)
322                kdebug ("\n")
323                break
324

Archive Download this file

Branches:
master



interactive