Changes in uspace/drv/char/sun4v-con/sun4v-con.c [dd8ab1c:7aa94304] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/char/sun4v-con/sun4v-con.c
rdd8ab1c r7aa94304 1 1 /* 2 2 * Copyright (c) 2008 Pavel Rimsky 3 * Copyright (c) 201 7Jiri Svoboda3 * Copyright (c) 2011 Jiri Svoboda 4 4 * All rights reserved. 5 5 * … … 36 36 #include <ddi.h> 37 37 #include <errno.h> 38 #include <str_error.h> 39 #include <io/chardev_srv.h> 38 #include <ipc/char.h> 40 39 #include <stdbool.h> 40 #include <sysinfo.h> 41 #include <thread.h> 41 42 42 43 #include "sun4v-con.h" … … 46 47 #define POLL_INTERVAL 10000 47 48 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 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); 55 66 56 67 static void sun4v_con_putchar(sun4v_con_t *con, uint8_t data) 57 68 { 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; 68 71 } 69 72 70 73 /** Add sun4v console device. */ 71 int sun4v_con_add(sun4v_con_t *con , sun4v_con_res_t *res)74 int sun4v_con_add(sun4v_con_t *con) 72 75 { 73 76 ddf_fun_t *fun = NULL; 74 77 int rc; 75 78 76 con->res = *res; 77 con->input_buffer = (niagara_input_buffer_t *) AS_AREA_ANY; 79 input_buffer = (input_buffer_t) AS_AREA_ANY; 78 80 79 81 fun = ddf_fun_create(con->dev, fun_exposed, "a"); … … 84 86 } 85 87 86 chardev_srvs_init(&con->cds);87 con->cds.ops = &sun4v_con_chardev_ops;88 con->cds.sarg = con;89 90 88 ddf_fun_set_conn_handler(fun, sun4v_con_connection); 91 89 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); 94 92 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); 103 99 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; 107 108 108 109 rc = ddf_fun_bind(fun); … … 112 113 } 113 114 114 ddf_fun_add_to_category(fun, "console");115 116 115 return EOK; 117 116 error: 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); 123 121 124 122 if (fun != NULL) … … 140 138 } 141 139 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 */ 144 static void sun4v_key_pressed(sun4v_con_t *con) 145 { 149 146 char c; 150 147 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 */ 164 static 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 } 179 172 } 180 173 … … 183 176 void *arg) 184 177 { 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 } 189 217 } 190 218
Note:
See TracChangeset
for help on using the changeset viewer.