1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-04-21 12:27:27 +03:00

make keyboard work a bit

This commit is contained in:
Bas Wijnen
2009-07-27 20:03:58 +02:00
parent 283b97955d
commit 561535234d
9 changed files with 454 additions and 60 deletions

View File

@@ -19,9 +19,146 @@
#ifndef __IRIS_DEVICES_HH
#define __IRIS_DEVICES_HH
#include "iris.h"
// This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves.
enum init_requests:
INIT_SET_GPIO_0
INIT_SET_GPIO_1
INIT_SET_LCD
// Keyboard interface.
// Startup: kbd_set_cb
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
static __inline__ void keyboard_set_cb (Capability kbd_set_cb, Capability cb):
invoke_10 (kbd_set_cb, cb)
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
#define KEYBOARD_RELEASE (1 << 31)
// Display interface.
// Startup: disp_set_eof_cb, disp_create_fb, disp_use_fb, disp_info
// Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
static __inline__ void display_set_eof_cb (Capability disp_set_eof_cb, Capability cb):
invoke_10 (disp_set_eof_cb, cb)
// Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
static __inline__ unsigned display_create_framebuffer (Capability disp_create_fb, Capability page0, Capability page1 = 0, Capability page2 = 0, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return call_n33 (disp_create_fb, page0, page1, page2, w, h, mode)
// Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested.
static __inline__ void display_use_framebuffer (Capability disp_use_fb, unsigned addr, Capability unuse_cb, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
invoke_11 (disp_use_fb, unuse_cb, addr)
// Get information about the display.
static __inline__ void display_get_info (Capability disp_info):
// TODO: Interface is to be designed.
// File system interface.
// This may not be a server, so there need not be a startup phase. Instead, capabilities can implement certain interfaces: directory, file, stream, seekable file, mappable file. Normal files implement at least stream or seekable file. Directories implement directory.
enum File_request:
FILE_INFO
FILE_CLOSE
FILE_COPY_HANDLE
DIRECTORY_GET_SIZE
DIRECTORY_GET_NAME
DIRECTORY_GET_FILE
DIRECTORY_GET_FILE_INFO
DIRECTORY_CREATE_FILE
DIRECTORY_DELETE_FILE
FILE_STREAM_READ
FILE_STREAM_WRITE
FILE_SEEKABLE_READ
FILE_SEEKABLE_WRITE
FILE_SEEKABLE_TRUNCATE
// File interface.
// Get information about the file.
static __inline__ unsigned long long file_get_info (Capability file, unsigned type):
return call_l02 (file, FILE_INFO, type)
// Close a file. If this is a directory, it implicitly closes all files opened from it.
static __inline__ void file_close (Capability file):
invoke_01 (file, FILE_CLOSE)
// Copy a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
static __inline__ Capability file_copy_handle (Capability file):
return call_c01 (file, FILE_COPY_HANDLE)
// Directory interface.
// Get the number of entries in this directory.
static __inline__ unsigned long long directory_get_size (Capability dir):
return call_l01 (dir, DIRECTORY_GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself.
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page):
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
// Get the file.
static __inline__ Capability directory_get_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
// Get file info. This returns the same information as file_get_info, without opening the file.
static __inline__ unsigned long long directory_get_file_info (Capability dir, unsigned long long idx, unsigned type):
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type)
// Create a new file. After this, any index may map to a different file.
static __inline__ Capability directory_create_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
// Delete a file. After this, any index may map to a different file.
static __inline__ Capability directory_delete_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
// Stream interface.
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_stream_read (Capability file, Capability page, unsigned size):
return call_n12 (file, page, FILE_STREAM_READ, size)
// Try to write size bytes. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_stream_write (Capability file, Capability page, unsigned size):
return call_n12 (file, page, FILE_STREAM_WRITE, size)
// Seekable file interface.
// Try to read size bytes from position idx. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_seekable_read (Capability file, Capability page, unsigned long long idx, unsigned size):
return call_n14 (file, page, FILE_SEEKABLE_READ, idx & 0xffffffff, idx >> 32, size)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_seekable_write (Capability file, Capability page, unsigned long long idx, unsigned size):
return call_n14 (file, page, FILE_SEEKABLE_WRITE, idx & 0xffffffff, idx >> 32, size)
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
static __inline__ void file_seekable_truncate (Capability file, unsigned long long idx):
call_n03 (file, FILE_SEEKABLE_TRUNCATE, idx & 0xffffffff, idx >> 32)
// Mappable file interface.
// TODO: to be designed.
// Block device interface.
// Startup: blk_get_size, blk_get_file.
// Get block size.
static __inline__ unsigned block_get_size (Capability blk_get_size):
return call_n00 (blk_get_size)
// Get file capability. Returns a seekable mappable non-stream file.
static __inline__ Capability block_get_file (Capability blk_get_file):
call_c00 (blk_get_file)
// TODO.
// Sound interface.
// Usb interfaces (port, device).
// Pointer interface. (Only movement; buttons follow keyboard interface.)
// Network interface.
// Camera interface.
// Terminal interfaces.
#endif

View File

@@ -21,7 +21,7 @@
#include "arch.hh"
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events
#define ALARM_INTERVAL (HZ / 1)
#define ALARM_INTERVAL (HZ / 20)
// GPIO pins for the devices (port.pin)
@@ -29,7 +29,7 @@
// 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.
// 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.
// touchpad buttons
// Left: 0.16
@@ -90,17 +90,22 @@ enum battery_type:
class Keyboard:
unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning
void parse (unsigned col, unsigned data):
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned code = (col << 3) | row
if data & (1 << row):
code |= 0x10000
code |= KEYBOARD_RELEASE
event (KEYBOARD_EVENT, code)
keys[col] = data
// If any keys are pressed, scanning is required.
if data != GPIO_KBD_ROW_MASK:
scanning = true
public:
bool is_scanning ():
return scanning
void scan ():
kdebug ("keyboard scan\n")
// Disable interrupts during scan.
GPIO_GPIER (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// All columns are input.
@@ -108,31 +113,34 @@ class Keyboard:
int const cols[GPIO_KBD_NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
unsigned dir = GPIO_GPDIR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
unsigned data
// Set scanning to false before first parse.
scanning = false
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
// clear pin
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// output
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Generate events of previous column. Do that now, so there is a short delay for the data to stabilize.
if col != 0:
parse (col - 1, data)
else:
// Add a short delay for stabilization.
parse (0, keys[0])
data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
for unsigned i = 0; i < 100000; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
parse (col, data)
// set pin
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
// input
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir
parse (GPIO_KBD_NUM_COLS - 1, data)
// set all to 0.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// set all to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// clear pending interrupts.
// Set interrupts on change.
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
for unsigned i = 0; i < 8; ++i:
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= 1 << i
if data & (1 << i):
gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
else:
gpio_irq_rise (GPIO_KBD_ROW_PORT, i)
// Clear pending interrupts.
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
// Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard ():
@@ -143,9 +151,6 @@ class Keyboard:
// Set all rows to input and enable the pull-ups.
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Detect interrupts on falling edge.
for unsigned i = 0; i < GPIO_KBD_NUM_ROWS; ++i:
gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
// Initialize matrix.
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i:
keys[i] = 0xff
@@ -174,6 +179,8 @@ class Touchpad:
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 0x10001)
old_state = state
// Ack interrupts.
GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
Touchpad ():
// Set pins to input with pull-ups.
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
@@ -313,17 +320,13 @@ int main ():
switch msg.protected_data:
case ~0:
// Alarm.
kdebug ("alarm\n")
// Periodically scan several devices.
kbd.scan ()
if kbd.is_scanning ():
kbd.scan ()
power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break
case IRQ_GPIO0:
kdebug ("gpio interrupt\n")
//unsigned irq = GPIO_GPFR (0)
// Ack all.
GPIO_GPFR (0) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
// Always scan keyboard and touchpad on any interrupt.
kbd.scan ()
tp.check_events ()