Difference between revisions of "Kernel interface"

From Pandora Wiki
Jump to: navigation, search
(updates)
(document display subsystem a bit)
Line 1: Line 1:
'''Warning''': this is preliminary and is subject to change until release.
+
'''Warning''': if your goal is just to write a game/program use higher level libraries/interfaces like SDL, Qt, X or similar for your own good (portability). It may be impossible to retain this layout on some major hardware revision, let's say Pandora 3000, and your program will break. Also this requires some level of Linux programming knowledge.
  
 
In case you need to write low level code (you can't/don't want to use high level libs like SDL), you can use kernel interface. This is the recommended way to access hardware (as opposed to GP2X style of accessing chip registers by mmap'ing /dev/mem), because in case hardware changes are needed in future, they could be handled by kernel and all programs would still work. It also should allow several programs to work at the same time and should be more stable.
 
In case you need to write low level code (you can't/don't want to use high level libs like SDL), you can use kernel interface. This is the recommended way to access hardware (as opposed to GP2X style of accessing chip registers by mmap'ing /dev/mem), because in case hardware changes are needed in future, they could be handled by kernel and all programs would still work. It also should allow several programs to work at the same time and should be more stable.
  
 
==Input==
 
==Input==
'''Warning''': if your goal is just to read inputs use higher level libraries/interfaces like SDL, X input or similar for your own good (portability). It may be impossible to retain this layout on some major hardware revision, let's say Pandora 3000, and your program will break.
 
 
 
Buttons, keypad, touchscreen and nubs are all exposed through Linux event interface (EVDEV). All devices are represented by /dev/input/eventX files, which can be opened, read and queried (using ioctl calls). The reads can be synchronous (the read will only return when user does something, like presses the button), or asynchronous (the system will report what changed since the last time you asked).
 
Buttons, keypad, touchscreen and nubs are all exposed through Linux event interface (EVDEV). All devices are represented by /dev/input/eventX files, which can be opened, read and queried (using ioctl calls). The reads can be synchronous (the read will only return when user does something, like presses the button), or asynchronous (the system will report what changed since the last time you asked).
  
Line 79: Line 77:
  
 
==Video==
 
==Video==
Framebuffer device (/dev/fb0) is supported. More to come..
+
===Architecture===
 +
Framebuffer device (/dev/fbX) is supported. There are 3 framebuffers available (/dev/fb0, /dev/fb1 and /dev/fb2), which represent 3 graphics/video layers on OMAP3 by default (but can be reconfigured). Only /dev/fb0 is enabled by default.
 +
 
 +
OMAP3 display subsystem is controlled by a driver known as DSS2, which has various controls available on /sys/devices/platform/omapdss/ (but they are not meant to be changed by programs, so they are root writable only). The driver exposes 3 layers (called overlays) and 2 displays. Overlays 1 and 2 can perform hardware scaling on the fly using 5-tap poly-phase filter, overlay0 can not. Displays 0 and 1 represent LCD and TV respectively. By default the 3 framebuffers (/dev/fbX) are redirected to 3 overlays, which all output to the LCD. This configuration is not meant to be changed by programs, only firmware should manage these.
 +
 
 +
===Basic usage===
 +
====framebuffer interface====
 +
Framebuffers can be accessed Linux fbdev interface:
 +
<source lang="c">
 +
fbdev = open("/dev/fb0", O_RDONLY);
 +
buffer = mmap(0, 800*480*2, PROT_WRITE, MAP_SHARED, fbdev, 0);
 +
</source>
 +
(this is basic example, no error checks)
 +
 
 +
the returned pointer can be used to draw on the screen.
 +
 
 +
====double buffering====
 +
This can be achieved using FBIOPAN_DISPLAY ioctl system call. For this you need to mmap framebuffer of double size
 +
<source lang="c">
 +
buffer1 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 0);
 +
buffer2 = (char *)mem + 800*480*2;
 +
</source>
 +
or map 2 buffers
 +
<source lang="c">
 +
buffer1 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 0);
 +
buffer2 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 800*480*2);
 +
</source>
 +
Then to display buffer2 you would call:
 +
<source lang="c">
 +
struct fb_var_screeninfo fbvar;
 +
ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
 +
fbvar.yoffset = 480;
 +
ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar);
 +
</source>
 +
going back to buffer1 would be repeating above with fbvar.yoffset = 0. Tripple or quad buffering can be implemented using the same technique.
 +
 
 +
====vertical sync====
 +
Linux has standard FBIO_WAITFORVSYNC for this:
 +
<source lang="c">
 +
int arg = 0;
 +
ioctl(fbdev, FBIO_WAITFORVSYNC, &arg);
 +
</source>
 +
be sure to pass argument value 0 or it will not work.
 +
 
 +
====hardware scaling====
 +
TODO
  
 
==LEDs and backlight==
 
==LEDs and backlight==

Revision as of 14:42, 8 June 2010

Warning: if your goal is just to write a game/program use higher level libraries/interfaces like SDL, Qt, X or similar for your own good (portability). It may be impossible to retain this layout on some major hardware revision, let's say Pandora 3000, and your program will break. Also this requires some level of Linux programming knowledge.

In case you need to write low level code (you can't/don't want to use high level libs like SDL), you can use kernel interface. This is the recommended way to access hardware (as opposed to GP2X style of accessing chip registers by mmap'ing /dev/mem), because in case hardware changes are needed in future, they could be handled by kernel and all programs would still work. It also should allow several programs to work at the same time and should be more stable.

Input

Buttons, keypad, touchscreen and nubs are all exposed through Linux event interface (EVDEV). All devices are represented by /dev/input/eventX files, which can be opened, read and queried (using ioctl calls). The reads can be synchronous (the read will only return when user does something, like presses the button), or asynchronous (the system will report what changed since the last time you asked).

Warning: don't hardcode device filenames in your program! For example, currently /dev/input/event2 represents game buttons, but in future it may become touchscreen. Scan input device names instead, example:

for (i = 0; 1; i++)
{
  sprintf(name, "/dev/input/event%i", i);
  fd = open(name, O_RDONLY);
  if (fd < 0) break; /* no more devices */
  ioctl(fd, EVIOCGNAME(sizeof(name)), name);
  if (strcmp(name, "gpio-keys") == 0)
    return fd; /* found the buttons! */
  close(fd); /* we don't need this device */
}

List of device names and events they send:

name description event.type event.code event.value
keypad keypad EV_KEY KEY_0...KEY_Z, KEY_BACKSPACE, KEY_LEFTSHIFT, KEY_SPACE, KEY_ENTER, KEY_COMMA, KEY_DOT, KEY_FN 0 - released, 1 - pressed, 2 - autorepeat event
gpio-keys game buttons EV_KEY KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_MENU (Pandora button), KEY_LEFTALT (Start), KEY_LEFTCTRL (Select), KEY_KP1 (Y/North), KEY_KP2 (A/East), KEY_KP3 (X/South), KEY_KP4 (B/West), KEY_KP5 (Shoulder L), KEY_KP6 (Shoulder R), KEY_KP7 (Shoulder L2), KEY_KP8 (Shoulder R2), KEY_COFFEE (Hold) 0 - released, 1 - pressed
gpio-keys lid state EV_SW SW_LID 0 - closing, 1 - opening
touchscreen touchscreen EV_ABS ABS_X, ABS_Y, ABS_PRESSURE varies, use calibration data
nub0 left nub EV_ABS ABS_X, ABS_Y -256 (Left/Up) ...0... +256 (Right/Down)
nub1 right nub EV_ABS ABS_X, ABS_Y -256 (Left/Up) ...0... +256 (Right/Down)

Sample code:
evtest.c op_test_inputs.c

Touchscreen

Event interface returns uncalibrated values directly from driver, so you need to use tslib or manage calibration yourself (using data from /etc/pointercal).

Sound

Pandora uses ALSA, but it has OSS emulation enabled too, so GP2X code should work.

Video

Architecture

Framebuffer device (/dev/fbX) is supported. There are 3 framebuffers available (/dev/fb0, /dev/fb1 and /dev/fb2), which represent 3 graphics/video layers on OMAP3 by default (but can be reconfigured). Only /dev/fb0 is enabled by default.

OMAP3 display subsystem is controlled by a driver known as DSS2, which has various controls available on /sys/devices/platform/omapdss/ (but they are not meant to be changed by programs, so they are root writable only). The driver exposes 3 layers (called overlays) and 2 displays. Overlays 1 and 2 can perform hardware scaling on the fly using 5-tap poly-phase filter, overlay0 can not. Displays 0 and 1 represent LCD and TV respectively. By default the 3 framebuffers (/dev/fbX) are redirected to 3 overlays, which all output to the LCD. This configuration is not meant to be changed by programs, only firmware should manage these.

Basic usage

framebuffer interface

Framebuffers can be accessed Linux fbdev interface:

fbdev = open("/dev/fb0", O_RDONLY);
buffer = mmap(0, 800*480*2, PROT_WRITE, MAP_SHARED, fbdev, 0);

(this is basic example, no error checks)

the returned pointer can be used to draw on the screen.

double buffering

This can be achieved using FBIOPAN_DISPLAY ioctl system call. For this you need to mmap framebuffer of double size

buffer1 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 0);
buffer2 = (char *)mem + 800*480*2;

or map 2 buffers

buffer1 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 0);
buffer2 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 800*480*2);

Then to display buffer2 you would call:

struct fb_var_screeninfo fbvar;
ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
fbvar.yoffset = 480;
ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar);

going back to buffer1 would be repeating above with fbvar.yoffset = 0. Tripple or quad buffering can be implemented using the same technique.

vertical sync

Linux has standard FBIO_WAITFORVSYNC for this:

int arg = 0;
ioctl(fbdev, FBIO_WAITFORVSYNC, &arg);

be sure to pass argument value 0 or it will not work.

hardware scaling

TODO

LEDs and backlight

The LEDs can be controlled via /sys/class/leds/, and then a file [1]:

  • pandora::sd1
  • pandora::sd2
  • pandora::charger
  • pandora::power
  • pandora::bluetooth
  • pandora::wifi
  • pandora::keypad_bl

Backlight can be controlled via /sys/class/backlight/.

Misc

Some things can be controlled through files in /proc/pandora/:

  • /proc/pandora/cpu_mhz_max - if cpufreq is enabled, sets maximum allowed cpu clock, if not, just sets CPU clock to value supplied (echo 600 > /proc/pandora/cpu_mhz_max). Might also just use cpufreq parameters themselves.

more to come..