Ignore:
File:
1 edited

Legend:

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

    r7aa94304 rdd8ab1c  
    11/*
    22 * Copyright (c) 2008 Pavel Rimsky
    3  * Copyright (c) 2011 Jiri Svoboda
     3 * Copyright (c) 2017 Jiri Svoboda
    44 * All rights reserved.
    55 *
     
    3636#include <ddi.h>
    3737#include <errno.h>
    38 #include <ipc/char.h>
     38#include <str_error.h>
     39#include <io/chardev_srv.h>
    3940#include <stdbool.h>
    40 #include <sysinfo.h>
    41 #include <thread.h>
    4241
    4342#include "sun4v-con.h"
     
    4746#define POLL_INTERVAL  10000
    4847
    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)
     48static int sun4v_con_read(chardev_srv_t *, void *, size_t, size_t *);
     49static int sun4v_con_write(chardev_srv_t *, const void *, size_t, size_t *);
    5550
    56 typedef 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 */
    63 static input_buffer_t input_buffer;
    64 
    65 static void sun4v_thread_impl(void *arg);
     51static chardev_ops_t sun4v_con_chardev_ops = {
     52        .read = sun4v_con_read,
     53        .write = sun4v_con_write
     54};
    6655
    6756static void sun4v_con_putchar(sun4v_con_t *con, uint8_t data)
    6857{
    69         (void) con;
    70         (void) data;
     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;
    7168}
    7269
    7370/** Add sun4v console device. */
    74 int sun4v_con_add(sun4v_con_t *con)
     71int sun4v_con_add(sun4v_con_t *con, sun4v_con_res_t *res)
    7572{
    7673        ddf_fun_t *fun = NULL;
    7774        int rc;
    7875
    79         input_buffer = (input_buffer_t) AS_AREA_ANY;
     76        con->res = *res;
     77        con->input_buffer = (niagara_input_buffer_t *) AS_AREA_ANY;
    8078
    8179        fun = ddf_fun_create(con->dev, fun_exposed, "a");
     
    8684        }
    8785
     86        chardev_srvs_init(&con->cds);
     87        con->cds.ops = &sun4v_con_chardev_ops;
     88        con->cds.sarg = con;
     89
    8890        ddf_fun_set_conn_handler(fun, sun4v_con_connection);
    8991
    90         sysarg_t paddr;
    91         rc = sysinfo_get_value("niagara.inbuf.address", &paddr);
     92        rc = physmem_map(res->in_base, 1, AS_AREA_READ | AS_AREA_WRITE,
     93            (void *) &con->input_buffer);
    9294        if (rc != EOK) {
    93                 ddf_msg(LVL_ERROR, "niagara.inbuf.address not set (%d)", rc);
     95                ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
    9496                goto error;
    9597        }
    9698
    97         rc = physmem_map(paddr, 1, AS_AREA_READ | AS_AREA_WRITE,
    98             (void *) &input_buffer);
     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);
    99103        if (rc != EOK) {
    100                 ddf_msg(LVL_ERROR, "Error mapping memory: %d", rc);
    101                 goto error;
     104                ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
     105                return rc;
    102106        }
    103 
    104         thread_id_t tid;
    105         rc = thread_create(sun4v_thread_impl, con, "kbd_poll", &tid);
    106         if (rc != EOK)
    107                 goto error;
    108107
    109108        rc = ddf_fun_bind(fun);
     
    113112        }
    114113
     114        ddf_fun_add_to_category(fun, "console");
     115
    115116        return EOK;
    116117error:
    117         /* XXX Clean up thread */
     118        if (con->input_buffer != (niagara_input_buffer_t *) AS_AREA_ANY)
     119                physmem_unmap((void *) con->input_buffer);
    118120
    119         if (input_buffer != (input_buffer_t) AS_AREA_ANY)
    120                 physmem_unmap((void *) input_buffer);
     121        if (con->output_buffer != (niagara_output_buffer_t *) AS_AREA_ANY)
     122                physmem_unmap((void *) con->output_buffer);
    121123
    122124        if (fun != NULL)
     
    138140}
    139141
    140 /**
    141  * Called regularly by the polling thread. Reads codes of all the
    142  * pressed keys from the buffer.
    143  */
    144 static void sun4v_key_pressed(sun4v_con_t *con)
     142/** Read from Sun4v console device */
     143static int sun4v_con_read(chardev_srv_t *srv, void *buf, size_t size,
     144    size_t *nread)
    145145{
     146        sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
     147        size_t p;
     148        uint8_t *bp = (uint8_t *) buf;
    146149        char c;
    147150
    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;
     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;
    158160        }
     161
     162        *nread = p;
     163        return EOK;
    159164}
    160165
    161 /**
    162  * Thread to poll Sun4v console for keypresses.
    163  */
    164 static void sun4v_thread_impl(void *arg)
     166/** Write to Sun4v console device */
     167static int sun4v_con_write(chardev_srv_t *srv, const void *data, size_t size,
     168    size_t *nwr)
    165169{
    166         sun4v_con_t *con = (sun4v_con_t *) arg;
     170        sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
     171        size_t i;
     172        uint8_t *dp = (uint8_t *) data;
    167173
    168         while (true) {
    169                 sun4v_key_pressed(con);
    170                 thread_usleep(POLL_INTERVAL);
    171         }
     174        for (i = 0; i < size; i++)
     175                sun4v_con_putchar(con, dp[i]);
     176
     177        *nwr = size;
     178        return EOK;
    172179}
    173180
     
    176183    void *arg)
    177184{
    178         sun4v_con_t *con;
     185        sun4v_con_t *con = (sun4v_con_t *) ddf_dev_data_get(
     186            ddf_fun_get_dev((ddf_fun_t *) arg));
    179187
    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         }
     188        chardev_conn(iid, icall, &con->cds);
    217189}
    218190
Note: See TracChangeset for help on using the changeset viewer.