1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2011 Alexander Warg <warg@os.inf.tu-dresden.de>,
4 *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
5 *               Adam Lackorzysnski <adam@os.inf.tu-dresden.de>
6 *     economic rights: Technische Universität Dresden (Germany)
7 *
8 * This file is part of TUD:OS and distributed under the terms of the
9 * GNU General Public License 2.
10 * Please see the COPYING-GPL-2 file for details.
11 *
12 * As a special exception, you may use this file as part of a free software
13 * library without restriction.  Specifically, if other files instantiate
14 * templates or use macros or inline functions from this file, or you compile
15 * this file and link it with other files to produce an executable, this
16 * file does not by itself cause the resulting executable to be covered by
17 * the GNU General Public License.  This exception does not however
18 * invalidate any other reasons why the executable file might be covered by
19 * the GNU General Public License.
20 */
21#pragma once
22
23#include <l4/sys/types.h>
24#include <l4/sys/vcon>
25#include <l4/sys/cxx/ipc_legacy>
26
27namespace L4Re { namespace Util {
28
29/**
30 * \brief Console server template class.
31 * \ingroup api_l4re_util
32 *
33 * This template uses vcon_write() and vcon_read() to get and deliver data
34 * from the implementor.
35 *
36 * vcon_read() needs to update the status argument with the
37 * L4_vcon_read_stat flags, especially the L4_VCON_READ_STAT_DONE flag
38 * to indicate that there's nothing more to read for the other end.
39 *
40 * vcon_write() gets the live data from the UTCB. Make sure to copy out the
41 * data before using the UTCB again.
42 *
43 * The size parameter of both functions is given in bytes.
44 */
45template< typename SVR >
46class Vcon_svr
47{
48public:
49  L4_RPC_LEGACY_DISPATCH(L4::Vcon);
50
51  l4_msgtag_t op_dispatch(l4_utcb_t *utcb, l4_msgtag_t tag, L4::Vcon::Rights)
52  {
53    l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
54    L4::Opcode op = m->mr[0];
55
56    switch (op)
57      {
58      case L4_VCON_WRITE_OP:
59        if (tag.words() < 3)
60          return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
61
62        this_vcon()->vcon_write((char const *)&m->mr[2], m->mr[1]);
63        return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
64
65      case L4_VCON_SET_ATTR_OP:
66        if (tag.words() < 4)
67          return l4_msgtag(-L4_EINVAL, 0, 0, 0);
68
69        return l4_msgtag(this_vcon()->vcon_set_attr((l4_vcon_attr_t const *)&m->mr[1]),
70                         0, 0, 0);
71
72      case L4_VCON_GET_ATTR_OP:
73        return l4_msgtag(this_vcon()->vcon_get_attr((l4_vcon_attr_t *)&m->mr[1]),
74                         4, 0, 0);
75
76      default:
77        break;
78      }
79
80    unsigned size = op >> 16;
81
82    if (size > (L4_UTCB_GENERIC_DATA_SIZE - 1) * sizeof(l4_utcb_mr()->mr[0]))
83      size = (L4_UTCB_GENERIC_DATA_SIZE - 1) * sizeof(l4_utcb_mr()->mr[0]);
84
85    char buf[size];
86    // Hmm, could we avoid the double copy here?
87    l4_umword_t v = this_vcon()->vcon_read(buf, size);
88    unsigned bytes = v & L4_VCON_READ_SIZE_MASK;
89
90    if (bytes < size)
91      v |= L4_VCON_READ_STAT_DONE;
92
93    m->mr[0] = v;
94    __builtin_memcpy(&m->mr[1], buf, bytes);
95
96    return l4_msgtag(0,
97                     (bytes + sizeof(l4_umword_t) - 1) / sizeof(l4_umword_t) + 1,
98                     0, 0);
99  }
100
101  unsigned vcon_read(char *buf, unsigned size) noexcept;
102  void vcon_write(const char *buf, unsigned size) noexcept;
103  int vcon_set_attr(l4_vcon_attr_t const *) noexcept
104  { return -L4_EOK; }
105  int vcon_get_attr(l4_vcon_attr_t *attr) noexcept
106  {
107    attr->l_flags = attr->o_flags = attr->i_flags = 0;
108    return -L4_EOK;
109  }
110
111private:
112  SVR const *this_vcon() const { return static_cast<SVR const *>(this); }
113  SVR *this_vcon() { return static_cast<SVR *>(this); }
114};
115
116}}
117