Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/sun4v-con/sun4v-con.c

    rdd8ab1c r7aa94304  
    11/*
    22 * Copyright (c) 2008 Pavel Rimsky
    3  * Copyright (c) 2017 Jiri Svoboda
     3 * Copyright (c) 2011 Jiri Svoboda
    44 * All rights reserved.
    55 *
     
    3636#include <ddi.h>
    3737#include <errno.h>
    38 #include <str_error.h>
    39 #include <io/chardev_srv.h>
     38#include <ipc/char.h>
    4039#include <stdbool.h>
     40#include <sysinfo.h>
     41#include <thread.h>
    4142
    4243#include "sun4v-con.h"
     
    4647#define POLL_INTERVAL  10000
    4748
    48 static int sun4v_con_read(chardev_srv_t *, void *, size_t, size_t *);
    49 static int sun4v_con_write(chardev_srv_t *, const void *, size_t, size_t *);
    50 
    51 static chardev_ops_t sun4v_con_chardev_ops = {
    52         .read = sun4v_con_read,
    53         .write = sun4v_con_write
    54 };
     49/*
     50 * Kernel counterpart of the driver pushes characters (it has read) here.
     51 * Keep in sync with the definition from
     52 * kernel/arch/sparc64/src/drivers/niagara.c.
     53 */
     54#define INPUT_BUFFER_SIZE  ((PAGE_SIZE) - 2 * 8)
     55
     56typedef volatile struct {
     57        uint64_t write_ptr;
     58        uint64_t read_ptr;
     59        char data[INPUT_BUFFER_SIZE];
     60} __attribute__((packed)) __attribute__((aligned(PAGE_SIZE))) *input_buffer_t;
     61
     62/* virtual address of the shared buffer */
     63static input_buffer_t input_buffer;
     64
     65static void sun4v_thread_impl(void *arg);
    5566
    5667static void sun4v_con_putchar(sun4v_con_t *con, uint8_t data)
    5768{
    58         if (data == '\n')
    59                 sun4v_con_putchar(con, '\r');
    60 
    61         while (con->output_buffer->write_ptr ==
    62             (con->output_buffer->read_ptr + OUTPUT_BUFFER_SIZE - 1)
    63             % OUTPUT_BUFFER_SIZE);
    64 
    65         con->output_buffer->data[con->output_buffer->write_ptr] = data;
    66         con->output_buffer->write_ptr =
    67             ((con->output_buffer->write_ptr) + 1) % OUTPUT_BUFFER_SIZE;
     69        (void) con;
     70        (void) data;
    6871}
    6972
    7073/** Add sun4v console device. */
    71 int sun4v_con_add(sun4v_con_t *con, sun4v_con_res_t *res)
     74int sun4v_con_add(sun4v_con_t *con)
    7275{
    7376        ddf_fun_t *fun = NULL;
    7477        int rc;
    7578
    76         con->res = *res;
    77         con->input_buffer = (niagara_input_buffer_t *) AS_AREA_ANY;
     79        input_buffer = (input_buffer_t) AS_AREA_ANY;
    7880
    7981        fun = ddf_fun_create(con->dev, fun_exposed, "a");
     
    8486        }
    8587
    86         chardev_srvs_init(&con->cds);
    87         con->cds.ops = &sun4v_con_chardev_ops;
    88         con->cds.sarg = con;
    89 
    9088        ddf_fun_set_conn_handler(fun, sun4v_con_connection);
    9189
    92         rc = physmem_map(res->in_base, 1, AS_AREA_READ | AS_AREA_WRITE,
    93             (void *) &con->input_buffer);
     90        sysarg_t paddr;
     91        rc = sysinfo_get_value("niagara.inbuf.address", &paddr);
    9492        if (rc != EOK) {
    95                 ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
    96                 goto error;
    97         }
    98 
    99         con->output_buffer = (niagara_output_buffer_t *) AS_AREA_ANY;
    100 
    101         rc = physmem_map(res->out_base, 1, AS_AREA_READ | AS_AREA_WRITE,
    102             (void *) &con->output_buffer);
     93                ddf_msg(LVL_ERROR, "niagara.inbuf.address not set (%d)", rc);
     94                goto error;
     95        }
     96
     97        rc = physmem_map(paddr, 1, AS_AREA_READ | AS_AREA_WRITE,
     98            (void *) &input_buffer);
    10399        if (rc != EOK) {
    104                 ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
    105                 return rc;
    106         }
     100                ddf_msg(LVL_ERROR, "Error mapping memory: %d", rc);
     101                goto error;
     102        }
     103
     104        thread_id_t tid;
     105        rc = thread_create(sun4v_thread_impl, con, "kbd_poll", &tid);
     106        if (rc != EOK)
     107                goto error;
    107108
    108109        rc = ddf_fun_bind(fun);
     
    112113        }
    113114
    114         ddf_fun_add_to_category(fun, "console");
    115 
    116115        return EOK;
    117116error:
    118         if (con->input_buffer != (niagara_input_buffer_t *) AS_AREA_ANY)
    119                 physmem_unmap((void *) con->input_buffer);
    120 
    121         if (con->output_buffer != (niagara_output_buffer_t *) AS_AREA_ANY)
    122                 physmem_unmap((void *) con->output_buffer);
     117        /* XXX Clean up thread */
     118
     119        if (input_buffer != (input_buffer_t) AS_AREA_ANY)
     120                physmem_unmap((void *) input_buffer);
    123121
    124122        if (fun != NULL)
     
    140138}
    141139
    142 /** Read from Sun4v console device */
    143 static int sun4v_con_read(chardev_srv_t *srv, void *buf, size_t size,
    144     size_t *nread)
    145 {
    146         sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
    147         size_t p;
    148         uint8_t *bp = (uint8_t *) buf;
     140/**
     141 * Called regularly by the polling thread. Reads codes of all the
     142 * pressed keys from the buffer.
     143 */
     144static void sun4v_key_pressed(sun4v_con_t *con)
     145{
    149146        char c;
    150147
    151         while (con->input_buffer->read_ptr == con->input_buffer->write_ptr)
    152                 async_usleep(POLL_INTERVAL);
    153 
    154         p = 0;
    155         while (p < size && con->input_buffer->read_ptr != con->input_buffer->write_ptr) {
    156                 c = con->input_buffer->data[con->input_buffer->read_ptr];
    157                 con->input_buffer->read_ptr =
    158                     ((con->input_buffer->read_ptr) + 1) % INPUT_BUFFER_SIZE;
    159                 bp[p++] = c;
    160         }
    161 
    162         *nread = p;
    163         return EOK;
    164 }
    165 
    166 /** Write to Sun4v console device */
    167 static int sun4v_con_write(chardev_srv_t *srv, const void *data, size_t size,
    168     size_t *nwr)
    169 {
    170         sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
    171         size_t i;
    172         uint8_t *dp = (uint8_t *) data;
    173 
    174         for (i = 0; i < size; i++)
    175                 sun4v_con_putchar(con, dp[i]);
    176 
    177         *nwr = size;
    178         return EOK;
     148        while (input_buffer->read_ptr != input_buffer->write_ptr) {
     149                c = input_buffer->data[input_buffer->read_ptr];
     150                input_buffer->read_ptr =
     151                    ((input_buffer->read_ptr) + 1) % INPUT_BUFFER_SIZE;
     152                if (con->client_sess != NULL) {
     153                        async_exch_t *exch = async_exchange_begin(con->client_sess);
     154                        async_msg_1(exch, CHAR_NOTIF_BYTE, c);
     155                        async_exchange_end(exch);
     156                }
     157                (void) c;
     158        }
     159}
     160
     161/**
     162 * Thread to poll Sun4v console for keypresses.
     163 */
     164static void sun4v_thread_impl(void *arg)
     165{
     166        sun4v_con_t *con = (sun4v_con_t *) arg;
     167
     168        while (true) {
     169                sun4v_key_pressed(con);
     170                thread_usleep(POLL_INTERVAL);
     171        }
    179172}
    180173
     
    183176    void *arg)
    184177{
    185         sun4v_con_t *con = (sun4v_con_t *) ddf_dev_data_get(
    186             ddf_fun_get_dev((ddf_fun_t *) arg));
    187 
    188         chardev_conn(iid, icall, &con->cds);
     178        sun4v_con_t *con;
     179
     180        /* Answer the IPC_M_CONNECT_ME_TO call. */
     181        async_answer_0(iid, EOK);
     182
     183        con = (sun4v_con_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
     184
     185        while (true) {
     186                ipc_call_t call;
     187                ipc_callid_t callid = async_get_call(&call);
     188                sysarg_t method = IPC_GET_IMETHOD(call);
     189
     190                if (!method) {
     191                        /* The other side has hung up. */
     192                        async_answer_0(callid, EOK);
     193                        return;
     194                }
     195
     196                async_sess_t *sess =
     197                    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
     198                if (sess != NULL) {
     199                        if (con->client_sess == NULL) {
     200                                con->client_sess = sess;
     201                                async_answer_0(callid, EOK);
     202                        } else
     203                                async_answer_0(callid, ELIMIT);
     204                } else {
     205                        switch (method) {
     206                        case CHAR_WRITE_BYTE:
     207                                ddf_msg(LVL_DEBUG, "Write %" PRIun " to device\n",
     208                                    IPC_GET_ARG1(call));
     209                                sun4v_con_putchar(con, (uint8_t) IPC_GET_ARG1(call));
     210                                async_answer_0(callid, EOK);
     211                                break;
     212                        default:
     213                                async_answer_0(callid, EINVAL);
     214                        }
     215                }
     216        }
    189217}
    190218
Note: See TracChangeset for help on using the changeset viewer.