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:
@@ -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
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
Reference in New Issue
Block a user