// vi:set ft=cpp: -*- Mode: C++ -*-
/**
 * \file
 * C++ Virtual console interface.
 */
/*
 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
 *               Alexander Warg <warg@os.inf.tu-dresden.de>,
 *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
 *     economic rights: Technische Universität Dresden (Germany)
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */
#pragma once

#include <l4/sys/icu>
#include <l4/sys/vcon.h>
#include <l4/sys/capability>

namespace L4 {

/**
 * C++ L4 Vcon interface, see \ref l4_vcon_api for the C interface.
 *
 * L4::Vcon is a virtual console for simple character-based input and output.
 * The interrupt for read events is provided by the virtual key interrupt.
 *
 * The Vcon interface inherits from L4::Icu and L4::Irq_eoi for managing the
 * virtual key interrupt which, in contrast to hardware IRQs, implements a
 * limited functionality:
 *  - Only IRQ line 0 is supported, no MSI vectors.
 *  - The IRQ is edge-triggered and the IRQ mode cannot be changed.
 *  - As the IRQ is edge-triggered, it does not have to be explicitly unmasked.
 *
 * A server implementing the virtual console protocol has a queue for input
 * events. When the first input event is added to the empty queue, the virtual
 * key interrupt is triggered. Further events are added to the queue without
 * generating further interrupts. The queue is emptied when a client reads all
 * queued input events.
 *
 * \includefile{l4/sys/vcon}
 *
 * See the \ref l4_vcon_api for the C interface.
 */
class Vcon :
  public Kobject_t<Vcon, Icu, L4_PROTO_LOG>
{
public:
  /**
   * Send data to `this` virtual console.
   *
   * \param buf   Pointer to the data buffer.
   * \param size  Size of the data buffer in bytes.
   * \utcb_def{utcb}
   *
   * \return Syscall return tag
   *
   * \note Size must not exceed #L4_VCON_WRITE_SIZE, a proper value of the
   *       `size` parameter is NOT checked. Also, this function is a send only
   *       operation, this means there is no return value except for a failed
   *       send operation. Use l4_ipc_error() to check for send errors, do not
   *       use l4_error(), as l4_error() will always return an error.
   */
  l4_msgtag_t
  send(char const *buf, unsigned size, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_send_u(cap(), buf, size, utcb); }

  /**
   * Write data to `this` virtual console.
   *
   * \param buf   Pointer to the data buffer.
   * \param size  Size of the data buffer in bytes.
   * \utcb_def{utcb}
   *
   * \retval <0   Error.
   * \retval >=0  Number of bytes written to the virtual console.
   */
  long
  write(char const *buf, unsigned size, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_write_u(cap(), buf, size, utcb); }

  /**
   * Read data from `this` virtual console.
   *
   * \param[out] buf   Pointer to data buffer.
   * \param      size  Size of the data buffer in bytes.
   * \utcb_def{utcb}
   *
   * \retval -L4_EPERM  Insufficient permissions; see precondition.
   * \retval >size      More bytes to read, `size` bytes are in the buffer `buf`.
   * \retval <=size     Number of bytes read.
   *
   * \pre The invoked Vcon capability must have the permission #L4_CAP_FPAGE_W.
   *
   * \note Size must not exceed #L4_VCON_READ_SIZE.
   */
  int
  read(char *buf, unsigned size, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_read_u(cap(), buf, size, utcb); }

  /**
   * Read data from `this` virtual console which also returns flags.
   *
   * \param[out] buf   Pointer to data buffer.
   * \param      size  Size of the data buffer in bytes.
   * \utcb_def{utcb}
   *
   * \retval -L4_EPERM  Insufficient permissions; see precondition.
   * \retval >size      More bytes to read, `size` bytes are in the buffer `buf`.
   * \retval <=size     Number of bytes read.
   *
   * \pre The invoked Vcon capability must have the permission #L4_CAP_FPAGE_W.
   *
   * If this function returns a positive value the caller can check the
   * #L4_VCON_READ_STAT_BREAK flag bit for a break condition. The bytes read
   * can be obtained by masking the return value with #L4_VCON_READ_SIZE_MASK.
   *
   * If a break condition is signaled, it is always the first event in the
   * transmitted content, i.e. all characters supplied by this read call follow
   * the break condition.
   *
   * \note Size must not exceed #L4_VCON_READ_SIZE.
   */
  int
  read_with_flags(char *buf, unsigned size, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_read_with_flags_u(cap(), buf, size, utcb); }

  /**
   * Set the attributes of `this` virtual console.
   *
   * \param attr  Attribute structure with the attributes for the virtual
   *              console.
   * \utcb_def{utcb}
   *
   * \return Syscall return tag.
   */
  l4_msgtag_t
  set_attr(l4_vcon_attr_t const *attr, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_set_attr_u(cap(), attr, utcb); }

  /**
   * Get attributes of `this` virtual console.
   *
   * \param[out] attr  Attribute structure. Contains the attributes after a
   *                   successful call of this function.
   * \utcb_def{utcb}
   *
   * \return Syscall return tag.
   */
  l4_msgtag_t
  get_attr(l4_vcon_attr_t *attr, l4_utcb_t *utcb = l4_utcb()) const noexcept
  { return l4_vcon_get_attr_u(cap(), attr, utcb); }

  typedef L4::Typeid::Raw_ipc<Vcon> Rpcs;
};

}
