Pocket Computing @ WRL

Documentation on Drivers


     
 

Overview

As of Release 4.0, a distinction is made between those drivers that must support the sessions interface and those that need not. Those that must support this interface are said to be sessions-aware.

Driver Sessions Aware Contact Person
Analog to Digital Converter n/a Larry Brakmo
Audio yes Debby Wallach
Battery n/a Larry Brakmo
Battery Monitor n/a Larry Brakmo
Buttons yes Debby Wallach
Clock speed no Debby Wallach
Display yes Larry Brakmo
Backlight n/a Larry Brakmo
Flash no Tim Mann
Keyboard no Larry Brakmo
Mcp n/a Debby Wallach
Power button yes Debby Wallach
Rock 'n' scroll yes Joel Bartlett
Real time clock no Debby Wallach
Serial n/a Debby Wallach
Sessions pseudo-device yes Larry Brakmo
Touchscreen yes Larry Brakmo
USB n/a Keith Farkas, & Larry Brakmo

General Information for Sessions-Aware Drivers

The new session-compliant user interface device drivers (touchscreen, buttons, sessions, ...) present their data as events that have a common header that is defined in <linux/include/linux/itsy_event.h>:

typedef struct {
  struct timeval timestamp; /* time when event was created */
  unsigned char  class;     /* class of event */
  unsigned char  type;      /* type of event (within its class) */
  unsigned char  size;      /* size of event in bytes */
  unsigned char  flags;     /* event flags */
} itsy_event_header;

The current classes are:
#define ITSY_EVENT_CLASS_SESSION     (1)
#define ITSY_EVENT_CLASS_DISPLAY     (2)
#define ITSY_EVENT_CLASS_TOUCHSCREEN (3)
#define ITSY_EVENT_CLASS_BUTTONS     (4)
#define ITSY_EVENT_CLASS_ADC         (5)

and the event flags are:
#define ITSY_EVENT_FLAG_NONE      (0x00)
#define ITSY_EVENT_FLAG_SYNTHETIC (0x01)
#define ITSY_EVENT_FLAG_GRABBED   (0x02)
#define ITSY_EVENT_FLAG_SUSER     (0x04)

Events are normally created as a result of the user interacting with the hardware, such as pressing a button or the touchscreen. Some drivers additionally support synthetic events that are created programatically and passed to the driver, usually via the write() system call. These events are marked with the ITSY_EVENT_FLAG_SYNTHETIC flag by the driver. If the program that created the synthetic event has super user privileges, the ITSY_EVENT_FLAG_SUSER flag is set in the event.

As mentioned in the sessions overview, events are delivered to processes that belong to the foreground session, and are not visible to processes in background sessions. However, there are times when a program may want to get events even when it is in the background (i.e., it is being executed by a process that belongs to a background session). This is accomplished by opening the appropriate raw device, making all the events from that device visible, regardless of whether the program is in the background or foreground. One type of program that would use this functionality is an application that records user interactions for later playback. This would be useful for demos or for macro creation.

Some drivers also support a grab operation that allows a program to grab a resource (or set of resources) from the driver. For example, a voice recorder program may grab a specific button so the user can always record a voice memo regardless of which program is foreground. Grabbed events are only available to the grabber and to readers of the raw device. Grabbed events are marked with the ITSY_EVENT_FLAG_GRABBED flag so raw readers will know that they are from a grabbed resource.

The following sections provide details for the various session-compliant Itsy device drivers:

The Analog-to-Digital Converter Driver

The UCB1200/1300 codec supports 4 analog to digital convertors (ADCs). The first one is connected to the battery on Itsy v1 and the battery's voltage can be read throught /dev/battery or /dev/adc (on a v2 the battery level can be obtained through /dev/battmon, see the Battery Monitor device driver documentation).

The include file is <linux/itsy_adc.h>.
The device name is /dev/adc.

The supported ioctls are: ADC_0_GET, ADC_1_GET, ADC_2_GET, ADC_3_GET. The adc returns values in the range of 0 to 1023. Here is an example:

ioctl(fd, ADC_1_GET, &adc1);

The Audio Driver

The Itsy audio driver supports interrupt-driven audio I/O via the Philips UCB1200/1300 codec. Both an Itsy-specific native API and the standard OSS "open sound system" API are supported. Clients may issue ioctl requests from either API, or even a mixture of both. It is recommended that clients use the OSS interface when possible for portability, and use the native interface only for operations that are not supported by OSS. Documentation for the OSS API is available from www.opensound.com.

The standard Linux include file for the OSS interface is <sys/soundcard.h>.
The include file for the Itsy-specific native interface is <linux/itsy_audio.h>.

Unlike the OSS model, which generally allows only one active client, the Itsy audio driver supports any number of simultaneous clients for both microphone input and speaker output. Microphone input is replicated for all active input clients, and speaker output is mixed for all active output clients. In the current implementation, audio output from all clients in background sessions is attenuated by approximately 12 dB, resulting in substantial volume reduction.

Note that the UCB1200/1300 hardware supports only a single sampling rate for both input and output. The current driver supports per-client output rates, and transparently performs sampling-rate conversion when necessary. This sample-rate conversion uses a crude linear interpolation approach; for better results, perform your own mixing in user-space by running sox or some other tool. The current implementation is also fairly inefficient, but since audio processing generally consumes less than 1% of the 200MHz Itsy CPU, we are not terribly motivated to optimize it.

Sample-rate conversion is not yet implemented for microphone input; this will be supported in a future release. However, a client can use the native AUDIO_LOCK_RATE ioctl to maintain a desired rate. Subsequent requests to change the microphone sample rate by other clients will fail.

The Itsy audio driver OSS implementation is intended to be complete. Although some of the less common ioctls have not been exhaustively tested, we have successfully compiled and used many applications such as sox without modification. However, memory-mapping the microphone buffer via the mmap() system call is supported only via the native API; it is currently unimplemented for OSS.

The Battery Driver

The battery device (only valid on v1) provides information about the current state of the Itsy batteries.

The include file is <linux/itsy_adc.h>.
The device name is /dev/battery.

A single ioctl, BATTERY_GET, is supported. It returns the voltage of the battery in opaque internal units that must be converted to volts through calibration:

ioctl(fd, BATTERY_GET, &bat);

The Battery Monitor Driver

Version 2 itsies have a Dallas Semiconductor Smart Battery Monitor (DS2437) that provides detailed information on the state of the battery.

The include file is <linux/itsy_battmon.h>.
The device name is /dev/battmon.

The device doesn't support reads or writes, only the ioctl interface. You should read the include file for full details.

Ioctls

ioctl(fd, BATTMON_DETECT, &id);
    /* Detect the battery monitor and return its 64b ROM code */
ioctl(fd, BATTMON_GET_TEMP, &temp);
    /* Return temperature, it may take up to one second */
ioctl(fd, BATTMON_GET_VOLTAGE, &vdd);
    /* Return Vdd voltage (battery voltage) */
ioctl(fd, BATTMON_VET_VAD_VOLTAGE, &vad);
    /* Return Vad voltage (external voltage) */
ioctl(fd, BATTMON_READ_CURRENT, &cur);
    /* Return the value of the current register (updated 32/sec) */
ioctl(fd, BATTMON_READ_NET_CURRENT, *netcur);
    /* Return value of net current (ICA) register. This register is 0
    when the battery is fully discharged, 100 when fully charged */

ioctl(fd, BATTMON_WRITE_NET_CURRENT, netcur);
    /* Set value of net current (ICA) register */
ioctl(fd, BATTMON_READ_CHARGING_CURRENT, &chargecur);
    /* Returns the value of the charging current (CCA) register.
    The CCA represents the total charging current the battery
    has encountered in its lifetime */

ioctl(fd, BATTMON_WRITE_CHARGING_CURRENT, chargecur);
    /* Set the value of CCA register */
ioctl(fd, BATTMON_READ_DISCHARGING_CURRENT, &dischargecur);
    /* Returns the value of the discharging current (DCA) register.
    The DCA represents the total discharging current the battery
    has encountered in its lifetime */

ioctl(fd, BATTMON_WRITE_DISCHARGING_CURRENT, dischargecur);
    /* Set the value of the DCA register */
ioctl(fd, BATTMON_READ_RTC, &rtc);
    /* Return value of RTC register. The timestamp is in units of 1 sec */
ioctl(fd, BATTMON_WRITE_RTC, rtc);
    /* Set the value of the RTC register */
ioctl(fd, BATTMON_READ_DISCONNECT_TIME, &disctime);
    /* Returns the value of the disconnect-timestamp register */
ioctl(fd, BATTMON_READ_EOC_TIME, &eoctime);
    /* Returns the value of the end-of-charge (EOC) register. */

The following ioctls are not directly related to the battery monitor but this seemed like the right driver to implement them.
ioctl(fd, BATTMON_SET_CHARGE_RATE, rate);
    /* If rate != 0, set fast charge rate (500ma current).
    Else set slow charge rate (100ma current) */

ioctl(fd, BATTMON_GET_CHARGE_RATE, &rate);
    /* Returns value of charge rate as defined above */
ioctl(fd, BATTMON_SET_CORE_VOLTAGE, corev);
    /* If corev != 0, set core voltage to high (1.5 V)
    else set core voltage to low (1.23 V) */

ioctl(fd, BATTMON_GET_CORE_VOLTAGE, &corev);
    /* Returns value of core voltage as defined above */

The Buttons Driver

The Itsy buttons driver supports interrupt-driven button input, and additionally provides a polling-based interface for backwards compatibility with earlier drivers.  The driver supports blocking and non-blocking I/O, select, asynchronous notifications, and synthetic events. Preliminary support for grabs has been implemented, but it has not been adequately tested.

The include file is <linux/itsy_buttons.h>.

The primary buttons devices are interrupt-driven and generate session-filtered button events that can be extracted via the read() system call:

/dev/buttons   buttons device
/dev/rbuttons  raw buttons device

A button event looks like:

typedef struct {
  itsy_event_header common;
  int sid;
  ushort state;
} itsy_buttons_event

As with all itsy events, the common header field includes a timestamp and other generic information. There is only one button event type; the field common.type is always ITSY_EVENT_BUTTONS_STATE. The state field is a bitmask containing the state of each button: 0=up, 1=down. The header file <linux/buttons.h> defines symbolic names for various button masks, such as BUTTON_SIDE_TOP, BUTTON_CURSOR_RIGHT, and BUTTON_CURSOR_ANY.

The backwards-compatible button devices have a polling interface (but are internally interrupt-driven). To poll the current device state, invoke the read() system call with a single unsigned long (32 bits):

/dev/buttons.poll   backwards-compatible polling interface
/dev/rbuttons.poll  raw backwards-compatible polling interface

The ulong read from a polling button device is a button bitmask with the same format described above. (The use of 32 vs. 16 bits is for backwards compatibility).

The buttons devices support the following ioctls, all of which are related to "grab" operations.  Although grabs are implemented, they have not been adequately tested.  In particular, grabs may not be properly reflected in the state obtained via the polling devices.

ushort mask;
ioctl(fd, BUTTONS_GET_GRAB_ALL, &mask);
    /* gets all grabs by all clients */
ioctl(fd, BUTTONS_GET_GRAB, &mask);
    /* gets grab mask for calling client */
ioctl(fd, BUTTONS_SET_GRAB, mask);
    /* sets grab mask for calling client */

On the V2 hardware, particular pairs of buttons share interrupts. Therefore, while any button is held down, the driver "polls" for any button state changes. Using the following ioctls, the polling rate, measured in jiffies, can be set by an application (but it will apply across all sessions). The polling can also be turned off or on (polling uses up a fair bit of time).

ulong poll_rate;
int poll_on_p;
ioctl(fd, BUTTONS_GET_POLL_RATE, &poll_rate);
ioctl(fd, BUTTONS_SET_POLL_RATE, poll_rate);
ioctl(fd, BUTTONS_DISABLE_POLL);
ioctl(fd, BUTTONS_ENABLE_POLL);
ioctl(fd, BUTTONS_POLL_IS_ENABLED, &poll_on_p);

The buttons are debounced in software.

Synthetic itsy_button_event events can be written to any of the buttons devices, and will be buffered for the session specified in the "sid" field.  If set to the special value ITSY_SESSION_ID_FOREGROUND, the event will be sent to the current foreground session. Like real events, synthetic events are session-filtered appropriately during subsequent read() system calls by clients.

The Clock Speed Driver

The processor clock can run at one of eleven clock levels, from 59.0 to 206.4Mhz (in approx 15Mhz increments). The code refers to the hardware index (0..10) rather than the actual clock speed. See Table 8.2 in the SA1100 manual concerning the clock configuration for more information.

In addition, you can enable/disable "clock switching". When swtiching is enabled, the CPU runs at 2x the DRAM clock speed until the processor needs to wait for a memory operation, at which time it runs at the DRAM clock speed until the operation is completed. With clock switching disabled, the CPU always runs at the DRAM clock speed (e.g. from 30-103MHz).

When the clock speed is changed, individual devices can (and should) be suspended during the speed change.

You should only use the following IOCTL's:

Getting information:

  • CLKSPEED_GET_CLOCK -- returns current clock speed index, or -1 on failure.
  • CLKSPEED_GET_SWITCHING -- returns one of the following:
    • -1 -- error
    • 0 -- switching is disabled
    • 1 -- switching is enabled

Setting information

  • CALL_IOCTL_CLKSPEED_SET_SPEED -- this macro should be used to set the clock speed and the state of "clock switching". You must also indicate if devices should suspend during the clock speed change. Normally, you will always specify TRUE for both switching and suspend. Parameters:
    • fd -- the file descriptor of the clock device (/dev/clkspeed)
    • speed -- the desired new speed (from 0 to 10, inclusive)
    • switching -- enable (1) or disable (0) switching after the speed change
    • suspend -- if 1, suspend devices during the switch; if 0, do not

    Typical use: retval = CALL_IOCTL_CLKSPEED_SET_SPEED(clockfd, newspeed, 1, 1);

The Display Driver

. Supports framebuffer allocation, framebuffer memory maping, framebuffer deallocation, LCD control (on, off, static), etc. There are no framebuffer related events. The include file is: <linux/itsy_fb.h> and the devices are:

/dev/fb        /* access visible framebuffer   */
/dev/fbdisplay
/dev/fbclone   /* allocates new framebuffers   */
/dev/fbvc      /* access framebuffer used in virtual consoles */
/dev/fbsession /* access session's visible framebuffer  */
/dev/fbnone    /* access framebuffer used when session has no
                * VC or framebuffer associated with it  */

Allocating a new framebuffer

Opening /dev/fbclone automatically allocates a new framebuffer. This framebuffer can be accessed by memory mapping (via the mmap() system call) the file descriptor returned when /dev/fbclone is opened. The framebuffer is automatically deallocated when there are no more references to it; i.e., when all outstanding opens are closed or the process terminates.

Example:

/* ... other includes related to I/O */
#include <linux/itsy_fb.h>
{
  unsigned char *fb;
  int fd;
  struct FbLcdParamsStruct fbLcdParams; /* framebuffer info */

  /* The open call allocates a new framebuffer */
  if ((fd = open("/dev/fbclone", O_RDWR)) >= 0) {

    /* get framebuffer information. For example,
     * framebuffer size is
     * fbLcdParams.screenSizeH x fbLcdParams.screenSizeV
     */
    if (ioctl(fd, FB_LCD_PARAMS, &fbLcdParams) == 0) {
      fb = (unsigned char *) mmap((caddr_t) NULL,
            fbLcdParams.frameBufferSize,
            PROT_READ | PROT_WRITE,
            MAP_FILE | MAP_SHARED, fd, 0);
      if (fb == (unsigned char *) -1)
        perror("ERROR: mmap framebuffer fails!\n");

      /* The first fbLcdParams.pixelDataOffset bytes are used
       * for the color map. Following that are the framebuffer
       * pixels, this is explained in the SA1100 reference
       * manual.
       */
    }
  }
}

Ioctls

ioctl(fd, FB_LCD_ON, 0L);
    /* Turns the LCD on */
ioctl(fd, FB_LCD_OFF, 0L);
    /* Turns the LCD off */
ioctl(fd, FB_LCD_STATIC, 0L);
    /* Makes the LCD go into static mode */
ioctl(fd, FB_LCD_SHOW, 0L);
    /* Show (i.e. make this the visible framebuffer for this
     * session) the framebuffer represented by the file
     * descriptor "fd".
     */
ioctl(fd, FB_LCD_PARAMS, fbLcdParams);
    /* Get framebuffer info (w, h, depth, etc) */

The Backlight Driver

The Epson LCD display on Itsy v2 units has a built-in LED based backlight. The hardware interface only supports on/off, but different brightness levels are supported through software by turning the LEDs on and off very quickly. For example, given a cycling frequency of 50Hz and a level of 70%, then every 20ms the LEDs are turned on for 14ms and off for 6ms.

The include file is <linux/itsy_bl.h>.
The device name is /dev/bl.

The device doesn't support reads or writes, only the ioctl interface.

Ioctls

ioctl(fd, BL_STATE_GET, &state);
    /* Returns 1 if the backlight is on, 0 if off */
ioctl(fd, BL_STATE_SET, state);
    /* Turn backlight on (state=1) or off (state=0) */
ioctl(fd, BL_FREQ_SET, freq);
    /* Set the cycling frequency */
ioctl(fd, BL_FREQ_GET, &freq);
    /* Returns the cycling frequency */
ioctl(fd, BL_LEVEL_GET, &level);
    /* Returns the backlight level */
ioctl(fd, BL_LEVEL_SET, level);
    /* Sets the backlight level */

The Keyboard Driver

Any ASCII characters written to /dev/kbd will be processed as if they have been entered through the keyboard (this is what scribble uses). /dev/kbdr is the raw interface, it interprets the input characters as keycodes (see linux/include/key_map.h), this is what the screen keyboard uses.

The Power Button Driver

The Itsy powerbutton driver supports interrupt-driven input for the distinguished physical powerbutton; i.e., the round white button on the face of the current Itsy prototypes (on the v2 Itsy units, the button is the one not part of the four-button cursor pad). This button is special because it is directly connected to an Itsy interrupt line; other button input is mediated by the codec. Like the ordinary buttons device, the powerbutton device generates itsy_buttons_event events that can be extracted via the read() system call.

This driver is also responsible for supporting the low-power SA1100 sleep mode. In earlier releases, this button was used exclusively for entering and leaving sleep mode. This is still the default behavior, but the current driver provides additional flexibility, allowing clients to directly manage the button and its association with sleep mode.

The include file is <linux/itsy_powerbutton.h>.
The device name is /dev/powerbutton.

By default, sleep mode is entered when the powerbutton is pressed. Each client may independently specify whether or not to respect this default. The device will enable the default sleep-mode behavior only when all clients agree to support it. A client may query or change its own local decision about entering sleep mode via the POWERBUTTON_GET_SLEEP and POWERBUTTON_SET_SLEEP ioctls. The global decision (across all clients) may be queried using POWERBUTTON_GET_SLEEP_ALL. Sleep mode can be requested directly from the POWERBUTTON_ENTER_SLEEP_MODE ioctl. Its argument, if non-zero, represents the amount of time it should sleep for (otherwise it will sleep until the powerbutton is pressed). Itsy v2 units also support the POWERBUTTON_ENTER_DEEP_SLEEP_MODE ioctl (a lower-power sleep mode that does not preserve the contents of DRAM). The supported ioctls are:

ioctl(fd, POWERBUTTON_SET_SLEEP, 0);
    /* disable sleep when the powerbutton is pressed. */
ioctl(fd, POWERBUTTON_SET_SLEEP, 1);
    /* enables sleep mode */
ioctl(fd, POWERBUTTON_GET_SLEEP, &v);
    /* query local sleep state */
ioctl(fd, POWERBUTTON_GET_SLEEP_ALL, &v);
    /* query global sleep state */
ioctl(fd, POWERBUTTON_ENTER_SLEEP_MODE,t);
    /* forcibly enter sleep mode (superuser); wake up after t seconds if t is > 0*/
ioctl(fd, POWERBUTTON_ENTER_DEEP_SLEEP_MODE);
    /* forcibly enter deep sleep mode (superuser)*/

The Rock 'n' Scroll Driver

Returns the most recent values generated by the two-axis ADXL202 accelerometer, http://www.analog.com/iMEMS/products/ADXL202.html.

Read: When the caller is part of the foreground session, 8 or more bytes of data of the following form are returned:

#define 
ADXL_SAMPLE_COUNT 1000 
struct ADXL_SAMPLE { int free; 
/* Index of first free entry */ int overflow; /* Buffer full so sample had to 
be flushed */ struct { unsigned int time; /* OS timer value */ unsigned int gpios; 
/* GPIO input values */ } samples[ ADXL_SAMPLE_COUNT ];
 
}
  • free is the number of valid entries in the samples array.
  • overflow is set to 1 when samples have been lost because the application has not kept up with the device.

Each time there is an edge transition on one or both of the gpio pins associated with the device, an interrupt occurs and an entry in the samples array is made. Each sample is of the form:

  • time is the value of the OS Timer Count Register (driven off the 3.6864-MHz clock) at the time of the IRQ_GPIO11_27 interrupt.
  • gpios is the value of the GPIO pins at the time of the interrupt, where bit 31 is the most significant bit. The two gpio pins used by Rock 'n' Scroll are:
    • #define GPIO_XAXIS 14
    • #define GPIO_YAXIS 15

Since entries are also made when other IRQ_GPIO11_27 interrupts occur, there may be entries with no signal change. Correct operation requires that there be only one reader of this device per session.

When the caller is not part of the foreground session, 0 bytes are returned.

Select: Returns following the next interrupt sample generation.

The Real Time Clock Driver

The real time clock driver provides three types of functions.

  • The first type either sets or reads the real time clock (get_cmos_time or set_cmos_time) and is called by the standard Linux settimeofday, gettimeofday, stime system calls.
  • The second type provide a real time clock based alarm which is currently only used by sleep mode code in the kernel. These include: void rtc_set_alarm(int seconds) - sets a real time clock alarm for seconds seconds from now. Only one alarm can be set at a time. void rtc_clear_alarm(void) - clears the alarm. int rtc_alarm_happened(void) - returns true iff an alarm went off and we were watching for it
  • The third type provides the sleep functions: rtc_suspend_check which always returns 0 (ie that immediate suspension is ok). rtc_suspend stores the difference between the wall time and the real time clock; rtc_resume resets the current wall clock time based on the time that passed during the sleep interval.

The Serial Driver

The serial driver conforms to the serial interface for Linux.

It also provides the sleep functions: For the most recently active port

  • rs_suspend_check returns the number of jiffies since the last activity.
  • rs_suspend blindly disables the serial ports, even if there's still data transmission, and saves the current state of the control registers, and
  • rs_resume restores the control registers to their previous state prior to the sleep.

The Session Pseudo-Device

The Itsy session driver manages information about active Itsy sessions. It exports both kernel and character-device interfaces. The include file is <linux/itsy_session.h>.

The kernel interface contains various operations to query, set, and receive callback notifications regarding sessions and changes in foreground/background status. The operation itsy_session_from_task() should be used by all session-compliant drivers to obtain the session identifier associated with a Linux task.  Function-level documentation for this kernel interface is available in the include file.

The normal device interface can be used by clients to obtain information about session events. It is expected that a distinguished session manager client will register itself (via the SESSION_SET_MANAGER ioctl, described below). In our current distribution, the gmanager application serves as the session manager. The manager is allowed to change the foreground session, and may also receive targeted messages from other clients (sent via the SESSION_MANAGER_REQUEST ioctl).

The driver currently supports non-blocking I/O and select (support for blocking reads is planned) on the following devices:

/dev/session   sessions device
/dev/rsession  raw sessions device

Session events can be extracted via the read() system call, and look like:

typedef struct {
  itsy_event_header common;
  int sid;
  itsy_session_request request;
} itsy_session_event;

As with all itsy events, the common header field includes a timestamp and other generic information. The field common.type specifies the type of session event associated with the session id specified by the sid field:

/* session event types */
#define ITSY_EVENT_SESSION_FOREGROUND  (1)
#define ITSY_EVENT_SESSION_BACKGROUND  (2)
#define ITSY_EVENT_SESSION_CREATED     (3)
#define ITSY_EVENT_SESSION_DESTROYED   (4)
#define ITSY_EVENT_SESSION_NAME        (5)
#define ITSY_EVENT_SESSION_DATA        (6)
#define ITSY_EVENT_SESSION_MANAGER_REQUEST (7)

FOREGROUND        sid became foreground session
BACKGROUND        sid became background session
CREATED           sid created
DESTROYED         sid destroyed
NAME              sid name updated
DATA              sid opaque data updated
MANAGER_REQUEST   special manager request

The session device supports the following ioctls:

int sid;

ioctl(fd, SESSION_GET_ID, &sid);
    /* get session id for calling client */
ioctl(fd, SESSION_GET_FOREGROUND, &sid);
    /* get foreground session id  */
ioctl(fd, SESSION_SET_FOREGROUND, sid);
    /* set foreground session id; fails unless manager */

typedef struct {
  int sid;
  itsy_session_name name;
} itsy_session_info;

itsy_session_info info;
info.sid = sid_to_query;

ioctl(fd, SESSION_GET_INFO, &info);
    /* get session name for info.sid */
ioctl(fd, SESSION_SET_INFO, &info);
    /* set session name for info.sid;
     * fails unless manager or caller sid */

typedef struct {
  int  sid;
  void *data;
  int  ndata;
  int  ntotal;
} itsy_session_data;

itsy_session_data data;

data.sid = sid_to_query;
ioctl(fd, SESSION_GET_DATA, &data);
    /* get opaque data assoc with data.sid */
ioctl(fd, SESSION_SET_DATA, &data);
    /* set opaque data assoc with data.sid;
     * fails unless manager or caller sid */

typedef struct {
  int *sids;
  int nsids;
  int ntotal;
} itsy_session_ids;

itsy_session_ids ids;
ids.nsids = 32;
ids.sids  = (int *) calloc(ids.nsids, sizeof(int));

ioctl(fd, SESSION_GET_IDS, &ids);
    /* get ids for all active sessions;
     * "ids.nsids" is an in/out parameter:
     * in  => max size of sids array
     * out => actual number copied
     * "ids.ntotal" is the total available
     */

The following ioctl is used to register or unregister the caller as the distinguished session manager:

ioctl(fd, SESSION_SET_MANAGER, 0);
    /* unregister caller as manager */
ioctl(fd, SESSION_SET_MANAGER, 1);
    /* register caller as manager;
     * fails if another manager registered */

The following manager operations are used to send Unix signals to all processes associated with the specified session id.  They fail with EPERM unless the caller is the distinguished manager:

ioctl(fd, SESSION_SIG_SUSPEND, sid);
    /* sends SIGSTOP to all sid processes */
ioctl(fd, SESSION_SIG_CONTINUE, sid);
    /* sends SIGCONT to all sid processes */
ioctl(fd, SESSION_SIG_TERMINATE, sid);
    /* sends SIGTERM to all sid processes */
ioctl(fd, SESSION_SIG_KILL, sid);
    /* sends SIGKILL to all sid processes */

typedef struct {
  int sender;
  int operation;
  int data;
} itsy_session_request;

The manager request operation is used by session clients to send a request to the session manager (if one exists). The sender field is automatically set to the client's session id. The operation and data fields are opaque, and are intended to be interpreted in a manager-specific way.

itsy_session_request r;
r.operation = MANAGER_SID_TO_FOREGROUND;
r.data = 0;
ioctl(fd, SESSION_MANAGER_REQUEST, &r);
    /* sends request r to session manager */

Touchscreen Driver

Supports blocking and non-blocking I/O, select, asynchronous notifications, synthetic events and grabs. The include file is: <linux/itsy_ts.h> and the touchscreen devices are:

/dev/ts       regular device
/dev/tsraw    raw device
/dev/tsgrab   interface to grab touchscreen areas

Touchscreen events look like:

typedef struct {
  ushort x;
  ushort y;
} ts_point;

typedef struct {
  itsy_event_header common;
  int sid;
  ushort pressure;
  ts_point point;
} ts_event;

Where:
 common.class  equals ITSY_EVENT_CLASS_TOUCHSCREEN
 common.type   there is only one type of event:
               ITSY_EVENT_TOUCHSCREEN
 sid           is the session id
 pressure      is the pressure on the touchscreen
 point         are the x,y coordinates of the pen on the screen

This is an energy efficient driver. When the touchscreen is not being pressed, it sets an interrupt so the driver can be notified when the touchscreen is pressed (and allows the MCP to go to sleep is no other device needs it). While the touchscreen in being pressed, events are created at a specified rate (default is 50/sec). When the pen (or finger) stops touching the screen, an event is created with the last (x,y) coordinates and zero pressure.

The rate can be changed on a per-session basis. When a session opens the touchscreen driver for the first time, its rate is set to the default (50/sec; this can be changed by a process with super-user privileges). The session rate can be changed with the TS_SET_RATE ioctl. Every time this session becomes the foreground session, the touchscreen rate will be set to the session's specified rate.

The coordinates read from the touchscreen hardware do not match the screen coordinates. The touchscreen driver maintains calibration information that is used to convert the hardware coordinates to the event coordinates read by programs. There is a global calibration and a per-client calibration (i.e., one for each open file descriptor). When a program opens the touchscreen driver, the per-client calibration is set to the global calibration. The program can later change its calibration with an ioctl. The following calibration structure is used to get or set the calibration:

typedef struct {
  int xscale;
  int xtrans;
  int yscale;
  int ytrans;
  int xyswap;
  int minp;
} ts_calibration;

The calibration algorithm is:

  if (xyswap) {
    cal_x = ((raw_y * xscale) >> 8) + xtrans;
    cal_y = ((raw_x * yscale) >> 8) + ytrans;
  } else {
    cal_x = ((raw_x * xscale) >> 8) + xtrans;
    cal_y = ((raw_y * yscale) >> 8) + ytrans;
  }

Note: the minp field is reserved for future use.

The touchscreen driver supports the following ioctls:

ts_calibration cal;

ioctl(fd, TS_SET_DEFAULT_CALIBRATION, &cal) sets global calibration
ioctl(fd, TS_GET_DEFAULT_CALIBRATION, &cal) gets global calibration
ioctl(fd, TS_SET_CALIBRATION, &cal)   sets per-session calibration
ioctl(fd, TS_GET_CALIBRATION, &cal)   gets per-session calibration

int rate; /* calibration rate in events/sec */

ioctl(fd, TS_SET_DEFAULT_RATE, rate)   sets global rate
ioctl(fd, TS_GET_DEFAULT_RATE, &rate)  gets global rate
ioctl(fd, TS_SET_RATE, rate)           sets per-session rate
ioctl(fd, TS_GET_RATE, &rate)          gets per-session rate;

The touchscreen driver supports one grabber at a time. The grabber is established by opening /dev/tsgrab and grab areas are added or deleted through ioctls. The following structure is used:

typedef struct {
  int    id;
  ts_point p0;
  ts_point p1;
} ts_grab_area;

Where p0 gives the coordinates of the upper left coordinate (and p1 of the lower right coordinate) of the rectangular area to be grabbed. Touchscreen events with x,y coordinates contained in a grabbed rectangular area (there can be more than one) are only seen by the grabber and by raw clients.

The grab ioctls are:

ts_grab_area garea;
long grabber_flag, id;

ioctl(fd, TS_ADD_GRAB_AREA, &garea);
    /* add a rectangular area to the grab list.
     * garea.id is set by the driver.
     */

ioctl(fd, TS_DELETE_GRAB_AREA, id);
    /* remove the grab area with the given id from the list.
     */

ioctl(fd, TS_GET_GRABBER, &grabber_flag);
    /* grabber_flag is set to 1 if there is a grabber,
     * 0 otherwise.
     */

 

The Itsy Project is a joint effort of the Western Research Lab and the Systems Research Center