Interface#

The device driver server in a Phoenix-RTOS ecosystem communicates with other processes using a message interface. In the typical case, the driver server has one port on which all requests are placed by clients. This port can be either registered within the native namespace or special file(s) can be created within the filesystem.

Port creation#

Port, the endpoint of the message communication, can be created using the portCreate() function. If zero is returned, then creation succeeded and the variable port now contains a unique port number assigned by the kernel.

Registering within a namespace#

The freshly created port can not be seen by other processes. To allow clients to find out the server’s port number, it has to be registered within some namespace. If the device driver server wants to register more than one “file” it does not have to create separate ports for them. The driver needs to assign each “file” ID from its private pool.

Assume we want to create an SPI server that manages 2 instances of the device - spi0 and spi1. We can manage both using only one port by registering the same port as /dev/spi0 with id = 1 and /dev/spi1 with id = 2. Every message driver receives contains information to which oid (object ID) it has been sent. This enables the driver to recognize to which special file message has been addressed.

If the system does not have a root filesystem, a port can be registered within Phoenix native filesystem by using syscall

int portRegister(u32 port, const char *name, oid_t *oid);

where

  • port - port number acquired from portCreate,

  • name - path in the namespace, e.g. “/uart0”,

  • oid - optional argument containing instance ID.

Syscall returns 0 on success.

On systems that contain filesystem special file can be created, which will point to the server’s oid. In the first place we need oid of directory which will hold our special file:

    #include <sys/msg.h>

    oid_t dir;

    lookup("/dev", &dir, NULL);

Then we can create a new special file and register:

    msg_t msg;

    msg.type = mtCreate;
    msg.oid = dir;
    msg.i.create.type = otDev;
    msg.i.create.mode = 0;
    msg.i.create.dev.port = port; /* Port number assigned by portCreate */
    msg.i.create.dev.id = id; /* Id assigned by the driver itself */
    msg.i.data = "drvfile"; /* Filename */
    msg.i.size = strlen(msg.i.data);
    msg.o.data = NULL;
    msg.o.size = 0;

    msgSend(dir.port, &msg);

Message passing mechanism is described in detail in the Interprocess communication - message queues document.

See also#

  1. Device drivers

  2. Access to device hardware registers

  3. Handling interrupts

  4. Table of Contents