TXT device API

A) General principles

The TXT device allows the kernel to access a text terminal peripheral, seen as two (TX & RX) streams of characters.

It is a multi-channel device, and there is one chdev per channel and per direction (TX/RX).

The TXT0 (channel 0) is the kernel terminal, and is only used to display debug or log messages.

The "kernel" API, contains the functions used by the system calls, and by the kernel itself. It defines three operation types : TXT_READ, TXT_WRITE, and TXT_SYNC_WRITE. This API is detailed in section C below.

The asynchronous TXT_READ and TXT_WRITE operations are not directly executed by the client thread. The requests are registered in the waiting queue rooted in the TXT chdev descriptor. These requests are actually handled by a dedicated server thread running in the cluster containing the chdev descriptor, that call the generic txt_driver_cmd() function for each registered request. A TXT_WRITE operation (TX direction) moves N characters from a kernel buffer to the TXT terminal. A TXT_READ operation (RX direction) moves one single character from the TXT terminal to a kernel buffer.

The synchronous SYNC_WRITE operation is used by the kernel to display debug messages on the TXT0. It does not use the waiting queue, and it does not use the server thread. The client thread calls directly the txt_driver_aux() function, without using the the txt_command_t structure to communicate with the driver.

Most TXT device implementations use two (hardware or software) FIFOs for asynchronous READ and WRITE operations. These FIFOs are not controlled by the kernel, but are accessed by the txt_driver_cmd() and txt_cxd_isr() function. When they are used by the driver, the TXT_TX_IRQ and TXT_RX_IRQ are routed to the core executing the corresponding TXT server thread. (ISR stand for Interrupt Service Routine).

The lower level "driver" API is detailed in section D below.

All TXT device structures and access functions are defined in the dev_txt.c et dev_txt.h files.

B) Initialisation

The TXT device dev_txt_init( chdev_t * chdev ) function makes the following initializations :

  • It selects a core in cluster containing the TXT chdev to execute the server thread.
  • it links the TXT channel IRQ to the core executing the server thread.
  • it initialises the TXT specific fields of the chdev descriptor.
  • it initialises the implementation specific TXT hardware device,
  • it initializes the specific software data structures required by the hardware implementation.

It must be called by a local thread.

C) The "kernel" API

These three I/O operations are blocking, and return only when the transfer is completed, but the blocking policy depends on the operation type.

C.1) Asynchronous operations

  • The dev_txt_read( uint32_t channel , char * buffer ) function moves one character from the terminal identified by the <channel> argument to the local kernel buffer identified by the <buffer> pointer.
  • The dev_txt_write( uint32_t channel , char * buffer , uint32_t count ) function moves <count> characters from a local kernel buffer identified by the <buffer> pointer, to the terminal identified by the <channel> argument.

Almos-mkh uses these asynchronous operations, for most data transfers required by the user processes. For a TX transter (TXT_WRITE), a fixed size kernel buffer is allocated in the kernel stack of the client thread.

The scenario is the following :

  1. When a client thread request an I/O operation, the request is registered in the ioc_command_t structure embedded in the client thread descriptor, and the client thread registers itself in the waiting queue rooted in the TXT chdev. Then the client thread blocks on the THREAD_BLOCKED_IO condition, and deschedules.
  2. The DEV server thread attached to the TXT device descriptor handles all commands registered in the TXT device waiting queue. For each pending request, it calls the txt_driver_cmd() function to move data between the kernel buffer and the TXT terminal. This txt_driver_cmd() function is itself a blocking function, returning only when the transfer is completed.
  3. When the txt_driver_cmd() function returns, the server thread reactivates the client thread, and handle the next request in the TXT waiting queue, or deschedules if the queue is empty.

Note : According to the scheduler policy, the DEV thread has an higher priority than any user thread, but it is not selected when the associated waiting queue is empty.

C.2) Synchronous operation

  • The dev_txt_sync_write( char * buffer , uint32_t count ) function moves <count> characters from the the kernel buffer identified by the <buffer> pointer, to the kernel TXT0 terminal.

Almost-mkh uses this operation to synchronously display debug or log messages on the kernel terminal, using the printk() kernel function, and we want to avoid any interference with another TXT I/O operation. We don't want to use the TXT device waiting queue, the associated server thread, and the txt_command_t structures used by the txt_driver_cmd() function. Therefore, this function directly call the txt_driver_aux() function, and the txt_sync_args_s structure for the arguments.

D) The "driver" API

All TXT drivers must define four functions :

  • void txt_driver_init( chdev_t *ioc_chdev )
  • void txt_driver_cmd( xptr_t thread_xp )
  • void txt_driver_isr( chdev_t * ioc_chdev )
  • void txt_driver_aux( char * buffer , uint32_t count )

The txt_driver_cmd() function is called for the TXT_READ and TXT_WRITE operations. The arguments are registered in the txt_command_t structure embedded in the client thread descriptor. One command contains three informations:

  • type : operation type (TXT_READ / TXT_WRITE)
  • buf_xp : extended pointer on kernel buffer.
  • count : number of characters (only for TXT_WRITE).

For these asynchronous operations, the txt_driver_cmd() function is called by the server thread:

  1. As most drivers implements, for each channel, two private software TX_FIFO and RX_FIDO, the txt_driver_cmd() function moves character(s) between the kernel buffer and the (TX or RX) FIFO. If the TX_FIFO is full (for a WRITE), or if the TX_FIFO is empty (for a READ), the server thread blocks on the THREAD_BLOCKED_ISR condition, and deschedules. It is re-activated by the txt_driver_isr() function, when the state of the blocking FIFO is modified.
  2. The txt_driver_isr() function is in charge of moving the characters between the (TX or RX) FIFO and the (TX or RX) buffer in the TXT terminal. It is called by the TXT_IRQ each time the TX buffer is empty, or each time the RX is FULL. ISR stand for Interrupt Service Routine. The txt_driver_isr() function re-activates the relevant server thread when the state of a blocking FIFO has been modified.

The txt_driver_aux() function is called for the TXT_SYNC_WRITE operation. The arguments are:

  • buffer : pointer on the kernel buffer.
  • count : number of characters to move.

For this synchronous operation, the txt_driver_cmd() function is called directly by the client thread. It does not use the TX_FIFO and the TXT_IRQ. It polls the TX buffer status to directly move the characters, from the kernel buffer to the terminal TX buffer.

Last modified 21 months ago Last modified on Jan 23, 2020, 12:22:35 AM