Subversion Repositories HelenOS

Rev

Rev 3582 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3549 rimsky 1
/*
2
 * Copyright (c) 2006 Ondrej Palkovsky
3
 * Copyright (c) 2008 Martin Decky
4
 * Copyright (c) 2008 Pavel Rimsky
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 * - Redistributions of source code must retain the above copyright
12
 *   notice, this list of conditions and the following disclaimer.
13
 * - Redistributions in binary form must reproduce the above copyright
14
 *   notice, this list of conditions and the following disclaimer in the
15
 *   documentation and/or other materials provided with the distribution.
16
 * - The name of the author may not be used to endorse or promote products
17
 *   derived from this software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 */
30
 
31
/** @defgroup sgcnfb SGCN
32
 * @brief   userland driver of the Serengeti console output
33
 * @{
34
 */
35
/** @file
36
 */
37
 
38
#include <async.h>
39
#include <ipc/ipc.h>
40
#include <ipc/fb.h>
41
#include <sysinfo.h>
42
#include <as.h>
43
#include <errno.h>
44
#include <stdio.h>
45
#include <ddi.h>
46
 
47
#include "sgcn.h"
48
 
49
#define WIDTH 80
50
#define HEIGHT 24
51
 
52
#define MAX_CONTROL 20
53
 
54
/**
55
 * Virtual address mapped to SRAM.
56
 */
57
static uintptr_t sram_virt_addr;
58
 
59
/**
60
 * SGCN buffer offset within SGCN.
61
 */
62
static uintptr_t sram_buffer_offset;
63
 
64
/* Allow only 1 connection */
65
static int client_connected = 0;
66
 
67
/**
68
 * SGCN buffer header. It is placed at the very beginning of the SGCN
69
 * buffer.
70
 */
71
typedef struct {
72
    /** hard-wired to "CON" */
73
    char magic[4];
74
 
75
    /** we don't need this */
76
    char unused[8];
77
 
78
    /** offset within the SGCN buffer of the input buffer start */
79
    uint32_t in_begin;
80
 
81
    /** offset within the SGCN buffer of the input buffer end */
82
    uint32_t in_end;
83
 
84
    /** offset within the SGCN buffer of the input buffer read pointer */
85
    uint32_t in_rdptr;
86
 
87
    /** offset within the SGCN buffer of the input buffer write pointer */
88
    uint32_t in_wrptr;
89
 
90
    /** offset within the SGCN buffer of the output buffer start */
91
    uint32_t out_begin;
92
 
93
    /** offset within the SGCN buffer of the output buffer end */
94
    uint32_t out_end;
95
 
96
    /** offset within the SGCN buffer of the output buffer read pointer */
97
    uint32_t out_rdptr;
98
 
99
    /** offset within the SGCN buffer of the output buffer write pointer */
100
    uint32_t out_wrptr;
101
} __attribute__ ((packed)) sgcn_buffer_header_t;
102
 
103
// TODO it is suggested to extract the common parts of this file and the msim.c file
104
// into a separate file and place that file to the genarch directory
105
 
106
/*
107
 * Returns a pointer to the object of a given type which is placed at the given
108
 * offset from the console buffer beginning.
109
 */
110
#define SGCN_BUFFER(type, offset) \
111
        ((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
112
 
113
/** Returns a pointer to the console buffer header. */
114
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
115
 
116
static void sgcn_putc(char c)
117
{
118
    uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
119
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
120
    uint32_t size = end - begin;
121
 
122
    /* we need pointers to volatile variables */
123
    volatile char *buf_ptr = (volatile char *)
124
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
125
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
126
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
127
 
128
    uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
129
    while (*out_rdptr_ptr == new_wrptr)
130
        ;
131
    *buf_ptr = c;
132
    *out_wrptr_ptr = new_wrptr;
133
}
134
 
135
static void sgcn_puts(char *str)
136
{
137
    while (*str)
138
        sgcn_putc(*(str++));
139
}
140
 
141
static void sgcn_goto(const unsigned int row, const unsigned int col)
142
{
143
    if ((row > HEIGHT) || (col > WIDTH))
144
        return;
145
 
146
    char control[20];
147
    snprintf(control, 20, "\033[%u;%uf", row + 1, col + 1);
148
    sgcn_puts(control);
149
}
150
 
151
static void sgcn_clrscr(void)
152
{
153
    sgcn_puts("\033[2J");
154
}
155
 
156
static void sgcn_scroll(int i)
157
{
158
    if (i > 0) {
159
        sgcn_goto(HEIGHT - 1, 0);
160
        while (i--)
161
            sgcn_puts("\033D");
162
    } else if (i < 0) {
163
        sgcn_goto(0, 0);
164
        while (i++)
165
            sgcn_puts("\033M");
166
    }
167
}
168
 
169
static void sgcn_set_style(const unsigned int mode)
170
{
171
    char control[MAX_CONTROL];
172
    snprintf(control, MAX_CONTROL, "\033[%um", mode);
173
    sgcn_puts(control);
174
}
175
 
176
static void sgcn_cursor_disable(void)
177
{
178
    sgcn_puts("\033[?25l");
179
}
180
 
181
static void sgcn_cursor_enable(void)
182
{
183
    sgcn_puts("\033[?25h");
184
}
185
 
186
static void sgcn_client_connection(ipc_callid_t iid, ipc_call_t *icall)
187
{
188
    int retval;
189
    ipc_callid_t callid;
190
    ipc_call_t call;
191
    char c;
192
    int lastcol = 0;
193
    int lastrow = 0;
194
    int newcol;
195
    int newrow;
196
    int fgcolor;
197
    int bgcolor;
198
    int i;
199
 
200
    if (client_connected) {
201
        ipc_answer_0(iid, ELIMIT);
202
        return;
203
    }
204
 
205
    client_connected = 1;
206
    ipc_answer_0(iid, EOK);
207
 
208
    /* Clear the terminal, set scrolling region
209
       to 0 - 24 lines */
210
    sgcn_clrscr();
211
    sgcn_goto(0, 0);
212
    sgcn_puts("\033[0;24r");
213
 
214
    while (true) {
215
        callid = async_get_call(&call);
216
        switch (IPC_GET_METHOD(call)) {
217
        case IPC_M_PHONE_HUNGUP:
218
            client_connected = 0;
219
            ipc_answer_0(callid, EOK);
220
            return;
221
        case FB_PUTCHAR:
222
            c = IPC_GET_ARG1(call);
223
            newrow = IPC_GET_ARG2(call);
224
            newcol = IPC_GET_ARG3(call);
225
            if ((lastcol != newcol) || (lastrow != newrow))
226
                sgcn_goto(newrow, newcol);
227
            lastcol = newcol + 1;
228
            lastrow = newrow;
229
            sgcn_putc(c);
230
            retval = 0;
231
            break;
232
        case FB_CURSOR_GOTO:
233
            newrow = IPC_GET_ARG1(call);
234
            newcol = IPC_GET_ARG2(call);
235
            sgcn_goto(newrow, newcol);
236
            lastrow = newrow;
237
            lastcol = newcol;
238
            retval = 0;
239
            break;
240
        case FB_GET_CSIZE:
241
            ipc_answer_2(callid, EOK, HEIGHT, WIDTH);
242
            continue;
243
        case FB_CLEAR:
244
            sgcn_clrscr();
245
            retval = 0;
246
            break;
247
        case FB_SET_STYLE:
248
            fgcolor = IPC_GET_ARG1(call);
249
            bgcolor = IPC_GET_ARG2(call);
250
            if (fgcolor < bgcolor)
251
                sgcn_set_style(0);
252
            else
253
                sgcn_set_style(7);
254
            retval = 0;
255
            break;
256
        case FB_SCROLL:
257
            i = IPC_GET_ARG1(call);
258
            if ((i > HEIGHT) || (i < -HEIGHT)) {
259
                retval = EINVAL;
260
                break;
261
            }
262
            sgcn_scroll(i);
263
            sgcn_goto(lastrow, lastcol);
264
            retval = 0;
265
            break;
266
        case FB_CURSOR_VISIBILITY:
267
            if(IPC_GET_ARG1(call))
268
                sgcn_cursor_enable();
269
            else
270
                sgcn_cursor_disable();
271
            retval = 0;
272
            break;
273
        default:
274
            retval = ENOENT;
275
        }
276
        ipc_answer_0(callid, retval);
277
    }
278
}
279
 
280
int sgcn_init(void)
281
{
282
    sram_virt_addr = (uintptr_t) as_get_mappable_page(sysinfo_value("sram.area.size"));
283
    int result = physmem_map(
284
        (void *) sysinfo_value("sram.address.physical"),
285
        (void *) sram_virt_addr,
286
        sysinfo_value("sram.area.size") / PAGE_SIZE,
287
        AS_AREA_READ | AS_AREA_WRITE
288
        );
289
    if (result != 0) {
290
        printf("SGCN: uspace driver couldn't map physical memory: %d\n",
291
            result);
292
    }
293
 
294
    sram_buffer_offset = sysinfo_value("sram.buffer.offset");
295
 
296
    async_set_client_connection(sgcn_client_connection);
297
    return 0;
298
}
299
 
300
/**
301
 * @}
302
 */
303