Device Driver Core

The device driver core facilitates registration and retrieval of devices.

It is implemented in os/drivers/core/device.c.

Implement device registration and retrieval

Initialization

The device driver core is initialized by calling

void device_init(void)

Initialize the device core.

^ Back to top.

Registering a New Device

A new device is allocated and registered by calling

int register_device(dev_id_t dev_id, const char *name, const file_operations_t *file_ops, void *priv_data)

Register a device.

Mark the major device number as used.

The registered device can later be retrieved via get_device() by its device id.

Parameters:
  • dev_id – the (major, minor) pair uniquely identifying the device

  • name – the name to be used for the device, e.g., in /dev; cannot be NULL or an empty string

  • file_ops – the file operations, e.g., open(), provided by this device

  • priv_data – driver specific, private data

Returns:

0 on sucess

Returns:

-ENOMEM, if there is no memory to create the device

Returns:

-EBUSY, if the same dev_id or name has already been registered

Returns:

-EINVAL, if name is NULL or points to an empty string

For registering the device, the pair of major and minor device id has to be unique. For a single major number, multiple minor numbers can exist. Unique minor device numbers have to be assigned by the driver implementing the device.

A new, still unused major number, can be retrieved and immediately marked as used by calling

int device_new_major(void)

Query and register a new, i.e., yet unused, major device number.

For dynamic major device number assignment, this function finds and registers a new/free major device number.

Returns:

a new major number, on success

Returns:

-ENOMEM, if no free major numbers are available

This function uses the internal helpers

static bool __device_major_available(uint8_t major)

Check if a device major number still free for use.

static void __device_register_major(uint8_t major)

Mark a device major number as used.

Which work on the bit mask storing used major numbers

static uint8_t __device_majors_used_mask[256 / 8]

A bitmask specifying which major numbers are in use.

^ Back to top.

Retrieving a Device

A registered device can be retrieved via its device id, i.e., the (major, minor) pair, by calling

const device_t *get_device(dev_id_t dev_id)

Retrieve a registered device.

If a device has been registered before a call to this function, the device can be retrieved via its device id passed in dev_id. The returned device can than be used to determine the required file operations for, e.g., opening the device.

Parameters:
  • dev_id – the (major, minor) pair uniquely identifying the device

Returns:

NULL if no such device has been registered.

^ Back to top.

Iterating Registered Devices

Registered devices can be iterated by using the following pair of functions

device_t *device_get_first(void)

Retrieve the first registered device, e.g., for iteration.

Returns:

a pointer to the first device

Returns:

NULL, if there is no registered device

device_t *device_get_next(device_t *dev)

Given a device dev, retrieve the next registered device.

Returns:

a pointer to the next device

Returns:

NULL, if there is no such device

Returns:

NULL, if dev is NULL or dev has not yet been registered

Alternatively, the following macro creates the head of a for loop over every registered device:

DEVICE_FOR_EACH(d)

Provide a for loop over every registered device d.

^ Back to top.

Data Structure Provided by the Device Core

The device driver core provides the following data structure

struct device_t

Device information.

Public Members

dev_id_t dev_id

The device id, i.e., major and minor device number.

char name[32]

The name of the device, e.g., for the nodes in /dev.

const file_operations_tfile_operations_t *file_ops

The file operations implemented by the device.

void *private_data

Driver internal private data, e.g., a gendisk of a block device.

^ Back to top.