diff --git a/.gitignore b/.gitignore index 703689b..cc44d59 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ uimage *.o *.cc *.hh -keyboard +gpio lcd diff --git a/boot-programs/gpio.ccp b/boot-programs/gpio.ccp new file mode 100644 index 0000000..a21a90c --- /dev/null +++ b/boot-programs/gpio.ccp @@ -0,0 +1,208 @@ +#pypp 0 +// Iris: micro-kernel for a capability-based operating system. +// boot-programs/gpio.ccp: GPIO driver, controlling all devices without special hardware. +// Copyright 2009 Bas Wijnen +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "devices.hh" +#define ARCH +#include "arch.hh" + +// GPIO pins for the devices (port.pin) + +// keyboard +// 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 +// Rows = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7 +// For some reason, it only works if the rows are input and the columns are output. +// interrupts: yes, with all columns set to output 0, the first key press can be detected as an interrupt. + +// touchpad buttons +// Left: 0.16 +// Right: 0.13 +// interrupts: yes, for any change. + +// Lock leds +// Num lock: 2.22 +// Caps lock: 0.27 +// Scroll lock: 0.9 +// interrupts: no, output only. + +// Power output (setting to 0 switches off the machine): 2.2 +// interrupts: no, output only. + +// Power button: 3.1 (note that this is also a keyboard column.) +// Battery presence and charge detection: 3.29 (note that this is also a keyboard column.) +// interrupts: no; it would be possible, but setting these to input makes it impossible to detect certain key presses as interrupts. + +class Keyboard: + enum { NUM_COLS = 17 } + enum { COL_MASK = 0x2000ffff } + enum { ROW_MASK = 0x000000ff } + + unsigned keys[NUM_COLS] + void event (bool release, unsigned row, unsigned col): + + public: + Keyboard (): + // Set all columns to input and disable the pull-ups. + GPIO_GPDIR (3) &= ~COL_MASK + GPIO_GPPUR (3) &= ~COL_MASK + + // Set all rows to input and enable the pull-ups. + GPIO_GPDIR (0) &= ~ROW_MASK + GPIO_GPPUR (0) |= ROW_MASK + // Enable interrupts on falling edge. + GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & 0xffff) | (GPIO_IRQ_FALLEDG * 0xaaaa) + GPIO_GPIER (0) |= 0xff + + for unsigned i = 0; i < NUM_COLS; ++i: + keys[i] = 0xff + void scan (): + // Set all columns to 0 when the become output. + GPIO_GPDR (3) &= ~COL_MASK + bool key_pressed = false + int const cols[NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 } + for unsigned col = 0; col < NUM_COLS; ++col: + GPIO_GPDIR (3) = (GPIO_GPDIR (3) & ~COL_MASK) | (1 << cols[col]) + udelay (100) + unsigned data = GPIO_GPDR (0) & ROW_MASK + // Generate events. + for unsigned row = 0; row < 8; ++row: + if (data ^ keys[col]) & (1 << row): + event (data & (1 << row), row, col) + keys[col] = data + if data != ROW_MASK: + key_pressed = true + if key_pressed: + // TODO: schedule keyboard scan. + +class Touchpad: + enum { LEFT = 1 << 16 } + enum { RIGHT = 1 << 13 } + unsigned old_state + void event (): + unsigned state = GPIO_GPDR (0) + if (state ^ old_state) & LEFT: + if state & LEFT: + GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_FALLEDG << (2 * 0)) + else: + GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_RAISEDG << (2 * 0)) + if (state ^ old_state) & RIGHT: + if state & RIGHT: + GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_FALLEDG << (2 * 13)) + else: + GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_RAISEDG << (2 * 13)) + old_state = state + public: + Touchpad (): + // Set pins to input with pull-ups. + GPIO_GPDIR (0) &= ~(LEFT | RIGHT) + GPIO_GPPUR (0) |= LEFT | RIGHT + // Enable interrupts. + GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_FALLEDG << (2 * 0)) + GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_FALLEDG << (2 * 13)) + old_state = 0 + // See if they are already pressed. If so, the interrupt detection is changed. + event () + // Now enable the interrupts. + GPIO_GPIER (0) |= LEFT | RIGHT + +class Lockleds: + // Note that num lock is in port 2. The others are in port 0. + enum { NUM = 1 << 22 } + enum { CAPS = 1 << 27 } + enum { SCROLL = 1 << 9 } + public: + Lockleds (): + GPIO_GPDR (2) &= ~NUM + GPIO_GPDR (0) &= ~(SCROLL | CAPS) + GPIO_GPDIR (2) |= NUM + GPIO_GPDIR (0) |= CAPS | SCROLL + void set (bool num, bool caps, bool scroll): + if num: + GPIO_GPDR (2) &= ~NUM + else: + GPIO_GPDR (2) |= NUM + if caps: + GPIO_GPDR (0) &= ~CAPS + else: + GPIO_GPDR (0) |= CAPS + if scroll: + GPIO_GPDR (0) &= ~SCROLL + else: + GPIO_GPDR (0) |= SCROLL + +class Power: + // Power out is in port 2, the rest in port 3. + enum { PWR_OUT = 1 << 2 } + enum { PWR_IN = 1 << 1 } + enum { BATTERY = 1 << 29 } + unsigned old_state + bool was_present + void poll (): + // Switch off keyboard interrupts, because this may interfere with them. + GPIO_GPIER (0) &= ~0xff + GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY) + GPIO_GPPUR (3) &= ~(PWR_IN | BATTERY) + udelay (100) + unsigned state = GPIO_GPDR (3) + if (state ^ old_state) & PWR_IN: + // TODO: event + if (state ^ old_state) & BATTERY: + if !(state & BATTERY): + GPIO_GPPUR (3) |= BATTERY + udelay (100) + if GPIO_GPDR (3) & BATTERY: + if !was_present: + // TODO: event + was_present = true + else: + if was_present: + // TODO: event + was_present = false + old_state = state + GPIO_GPPUR (3) &= ~BATTERY + GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY) + udelay (100) + GPIO_GPIER (3) |= 0xff + public: + Power (): + GPIO_GPDR (2) |= PWR_OUT + GPIO_GPDIR (2) |= PWR_OUT + was_present = true + old_state = BATTERY + poll () + void poweroff (): + GPIO_GPDR (2) &= ~PWR_OUT + while true: + // Do nothing; wait until the device stops running. + +int main (): + map_gpio () + + Keyboard kbd + Touchpad tp + Lockleds leds + Power power + + while true: + Message msg + wait (&msg) + switch msg.protected_data: + case IRQ_GPIO0: + case IRQ_GPIO1: + case IRQ_GPIO2: + case IRQ_GPIO3: + // TODO diff --git a/boot-programs/keyboard.ccp b/boot-programs/keyboard.ccp deleted file mode 100644 index 17fed17..0000000 --- a/boot-programs/keyboard.ccp +++ /dev/null @@ -1,73 +0,0 @@ -#pypp 0 -// Iris: micro-kernel for a capability-based operating system. -// boot-programs/keyboard.ccp: Testing userspace thread. -// Copyright 2009 Bas Wijnen -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "devices.hh" -#define ARCH -#include "arch.hh" - -// GPIO pins for the keyboard: (port.pin) -// 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 -// Rows = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7 -// For some reason, it only works if the rows are input and the columns are output. - -static void event (bool release, unsigned row, unsigned col): - -#define COL_MASK 0x2000ffff -#define ROW_MASK 0x000000ff - -int main (): - map_gpio () - - // Disable all interrupts. - GPIO_GPIER (3) &= ~COL_MASK - GPIO_GPIER (0) &= ~ROW_MASK - - // Set all to GPIO. - GPIO_GPALR (3) = 0 - GPIO_GPAUR (3) &= ~0x0c000000 - GPIO_GPALR (0) &= ~0x0003ffff - - // Set all rows to input and enable the pull-ups. - GPIO_GPDIR (0) &= ~ROW_MASK - GPIO_GPPUR (0) |= ROW_MASK - - // Set all columns to input and disable the pull-ups; set to 0 when output. - GPIO_GPDIR (3) &= ~COL_MASK - GPIO_GPPUR (3) &= ~COL_MASK - GPIO_GPDR (3) &= ~COL_MASK - - #define NUM_COLS 17 - unsigned keys[NUM_COLS] - for unsigned i = 0; i < NUM_COLS; ++i: - keys[i] = 0xff - - // Pin numbers for the cols, relative to the start of the port (so minus 0x60). - event (false, 0, 0) - int const cols[NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 } - while true: - // read keyboard - for unsigned col = 0; col < NUM_COLS; ++col: - GPIO_GPDIR (3) = (GPIO_GPDIR (3) & ~COL_MASK) | (1 << cols[col]) - udelay (100) - unsigned data = GPIO_GPDR (0) & ROW_MASK - // Generate events. - for unsigned row = 0; row < 8; ++row: - if (data ^ keys[col]) & (1 << row): - event (data & (1 << row), row, col) - keys[col] = data - schedule () diff --git a/mips/Makefile.arch b/mips/Makefile.arch index bf8d230..a23fb57 100644 --- a/mips/Makefile.arch +++ b/mips/Makefile.arch @@ -28,7 +28,7 @@ arch_kernel_sources = mips/interrupts.cc mips/test.cc mips/arch.cc boot_sources = mips/init.cc BUILT_SOURCES = $(kernel_sources) $(boot_sources) arch_headers = mips/arch.hh mips/jz4730.hh -boot_threads = keyboard lcd +boot_threads = gpio lcd uimage: diff --git a/mips/entry.S b/mips/entry.S index f9c883d..009e1ed 100644 --- a/mips/entry.S +++ b/mips/entry.S @@ -236,5 +236,5 @@ thread0: .incbin "lcd" .balign 0x1000 thread1: - .incbin "keyboard" + .incbin "gpio" thread2: diff --git a/mips/init.ccp b/mips/init.ccp index 1c3f1a4..9aec1b6 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -238,6 +238,13 @@ void init (unsigned mem): // Set up initial threads. init_threads () + // Disable all gpio pins initially. + for unsigned i = 0; i < 4; ++i: + GPIO_GPIER (i) = 0 + GPIO_GPDIR (i) = 0 + GPIO_GPPUR (i) = 0 + GPIO_GPALR (i) = 0 + GPIO_GPAUR (i) = 0 // Set up the rest of the hardware (copied from Linux). cpm_idle_mode () cpm_enable_cko1 () @@ -253,10 +260,6 @@ void init (unsigned mem): gpio_as_lcd_master () gpio_as_ssi() gpio_as_msc () - GPIO_GPDIR (GPIO_PWM0_PORT) |= 1 << GPIO_PWM0 - GPIO_GPDR (GPIO_PWM0_PORT) |= 1 << GPIO_PWM0 - GPIO_GPDIR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN - GPIO_GPDR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN // Start the operating system timer, and set it to give an interrupt immediately. // This is better, because the kernel starts with jumping into the idle task and