source: mainline/kernel/arch/sparc64/src/drivers/sgcn.c@ 214ec25c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 214ec25c was af24629, checked in by Jakub Jermar <jakub@…>, 15 years ago

Fix sparc64 debug build.
(Contributed by Igor Kovalenko.)

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2008 Pavel Rimsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sparc64
30 * @{
31 */
32/**
33 * @file
34 * @brief SGCN driver.
35 */
36
37#include <arch.h>
38#include <arch/drivers/sgcn.h>
39#include <arch/drivers/kbd.h>
40#include <genarch/ofw/ofw_tree.h>
41#include <debug.h>
42#include <str.h>
43#include <print.h>
44#include <mm/page.h>
45#include <proc/thread.h>
46#include <console/chardev.h>
47#include <console/console.h>
48#include <sysinfo/sysinfo.h>
49#include <synch/spinlock.h>
50
51#define POLL_INTERVAL 10000
52
53/*
54 * Physical address at which the SBBC starts. This value has been obtained
55 * by inspecting (using Simics) memory accesses made by OBP. It is valid
56 * for the Simics-simulated Serengeti machine. The author of this code is
57 * not sure whether this value is valid generally.
58 */
59#define SBBC_START 0x63000000000
60
61/* offset of SRAM within the SBBC memory */
62#define SBBC_SRAM_OFFSET 0x900000
63
64/* size (in bytes) of the physical memory area which will be mapped */
65#define MAPPED_AREA_SIZE (128 * 1024)
66
67/* magic string contained at the beginning of SRAM */
68#define SRAM_TOC_MAGIC "TOCSRAM"
69
70/*
71 * Key into the SRAM table of contents which identifies the entry
72 * describing the OBP console buffer. It is worth mentioning
73 * that the OBP console buffer is not the only console buffer
74 * which can be used. It is, however, used because when the kernel
75 * is running, the OBP buffer is not used by OBP any more but OBP
76 * has already made necessary arrangements so that the output will
77 * be read from the OBP buffer and input will go to the OBP buffer.
78 * Therefore HelenOS needs to make no such arrangements any more.
79 */
80#define CONSOLE_KEY "OBPCONS"
81
82/* magic string contained at the beginning of the console buffer */
83#define SGCN_BUFFER_MAGIC "CON"
84
85/*
86 * Returns a pointer to the object of a given type which is placed at the given
87 * offset from the SRAM beginning.
88 */
89#define SRAM(type, offset) ((type *) (instance->sram_begin + (offset)))
90
91/* Returns a pointer to the SRAM table of contents. */
92#define SRAM_TOC (SRAM(iosram_toc_t, 0))
93
94/*
95 * Returns a pointer to the object of a given type which is placed at the given
96 * offset from the console buffer beginning.
97 */
98#define SGCN_BUFFER(type, offset) \
99 ((type *) (instance->buffer_begin + (offset)))
100
101/** Returns a pointer to the console buffer header. */
102#define SGCN_BUFFER_HEADER (SGCN_BUFFER(sgcn_buffer_header_t, 0))
103
104static void sgcn_putchar(outdev_t *, const wchar_t, bool);
105
106static outdev_operations_t sgcndev_ops = {
107 .write = sgcn_putchar,
108 .redraw = NULL
109};
110
111static sgcn_instance_t *instance = NULL;
112
113/**
114 * Set some sysinfo values (SRAM address and SRAM size).
115 */
116static void register_sram(uintptr_t sram_begin_physical)
117{
118 sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
119 sysinfo_set_item_val("sram.address.physical", NULL,
120 sram_begin_physical);
121}
122
123/**
124 * Initializes the starting address of SRAM.
125 *
126 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
127 * physical memory, where C is the value read from the "iosram-toc"
128 * property of the "/chosen" OBP node. The sram_begin variable will
129 * be set to the virtual address which maps to the SRAM physical
130 * address.
131 */
132static void init_sram_begin(void)
133{
134 ASSERT(instance);
135
136 ofw_tree_node_t *chosen = ofw_tree_lookup("/chosen");
137 if (!chosen)
138 panic("Cannot find '/chosen'.");
139
140 ofw_tree_property_t *iosram_toc =
141 ofw_tree_getprop(chosen, "iosram-toc");
142 if (!iosram_toc)
143 panic("Cannot find property 'iosram-toc'.");
144 if (!iosram_toc->value)
145 panic("Cannot find SRAM TOC.");
146
147 uintptr_t sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
148 + *((uint32_t *) iosram_toc->value);
149 instance->sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
150
151 register_sram(sram_begin_physical);
152}
153
154/**
155 * Function regularly called by the keyboard polling thread. Finds out whether
156 * there are some unread characters in the input queue. If so, it picks them up
157 * and sends them to the upper layers of HelenOS.
158 */
159static void sgcn_poll(sgcn_instance_t *instance)
160{
161 uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
162 uint32_t end = SGCN_BUFFER_HEADER->in_end;
163 uint32_t size = end - begin;
164
165 if (silent)
166 return;
167
168 spinlock_lock(&instance->input_lock);
169
170 /* we need pointers to volatile variables */
171 volatile char *buf_ptr = (volatile char *)
172 SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
173 volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
174 volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
175
176 while (*in_rdptr_ptr != *in_wrptr_ptr) {
177 buf_ptr = (volatile char *)
178 SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
179 char c = *buf_ptr;
180 *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
181
182 indev_push_character(instance->srlnin, c);
183 }
184
185 spinlock_unlock(&instance->input_lock);
186}
187
188/**
189 * Polling thread function.
190 */
191static void ksgcnpoll(void *instance) {
192 while (true) {
193 if (!silent)
194 sgcn_poll(instance);
195
196 thread_usleep(POLL_INTERVAL);
197 }
198}
199
200/**
201 * Initializes the starting address of the SGCN buffer.
202 *
203 * The offset of the SGCN buffer within SRAM is obtained from the
204 * SRAM table of contents. The table of contents contains
205 * information about several buffers, among which there is an OBP
206 * console buffer - this one will be used as the SGCN buffer.
207 *
208 * This function also writes the offset of the SGCN buffer within SRAM
209 * under the sram.buffer.offset sysinfo key.
210 */
211static void sgcn_init(void)
212{
213 if (instance)
214 return;
215
216 instance = malloc(sizeof(sgcn_instance_t), FRAME_ATOMIC);
217
218 if (instance) {
219 instance->thread = thread_create(ksgcnpoll, instance, TASK, 0,
220 "ksgcnpoll", true);
221
222 if (!instance->thread) {
223 free(instance);
224 instance = NULL;
225 return;
226 }
227
228 init_sram_begin();
229
230 ASSERT(str_cmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
231
232 /* Lookup TOC entry with the correct key */
233 uint32_t i;
234 for (i = 0; i < MAX_TOC_ENTRIES; i++) {
235 if (str_cmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
236 break;
237 }
238 ASSERT(i < MAX_TOC_ENTRIES);
239
240 instance->buffer_begin =
241 instance->sram_begin + SRAM_TOC->keys[i].offset;
242
243 sysinfo_set_item_val("sram.buffer.offset", NULL,
244 SRAM_TOC->keys[i].offset);
245
246 instance->srlnin = NULL;
247 }
248}
249
250/**
251 * Writes a single character to the SGCN (circular) output buffer
252 * and updates the output write pointer so that SGCN gets to know
253 * that the character has been written.
254 */
255static void sgcn_do_putchar(const char c)
256{
257 uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
258 uint32_t end = SGCN_BUFFER_HEADER->out_end;
259 uint32_t size = end - begin;
260
261 /* We need pointers to volatile variables */
262 volatile char *buf_ptr = (volatile char *)
263 SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
264 volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
265 volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
266
267 /*
268 * Write the character and increment the write pointer modulo the
269 * output buffer size. Note that if we are to rewrite a character
270 * which has not been read by the SGCN controller yet (i.e. the output
271 * buffer is full), we need to wait until the controller reads some more
272 * characters. We wait actively, which means that all threads waiting
273 * for the lock are blocked. However, this situation is
274 * 1) rare - the output buffer is big, so filling the whole
275 * output buffer is improbable
276 * 2) short-lasting - it will take the controller only a fraction
277 * of millisecond to pick the unread characters up
278 * 3) not serious - the blocked threads are those that print something
279 * to user console, which is not a time-critical operation
280 */
281 uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
282 while (*out_rdptr_ptr == new_wrptr);
283
284 *buf_ptr = c;
285 *out_wrptr_ptr = new_wrptr;
286}
287
288/**
289 * SGCN output operation. Prints a single character to the SGCN. Newline
290 * character is converted to CRLF.
291 */
292static void sgcn_putchar(outdev_t *dev, const wchar_t ch, bool silent)
293{
294 if (!silent) {
295 spinlock_lock(&instance->output_lock);
296
297 if (ascii_check(ch)) {
298 if (ch == '\n')
299 sgcn_do_putchar('\r');
300 sgcn_do_putchar(ch);
301 } else
302 sgcn_do_putchar(U_SPECIAL);
303
304 spinlock_unlock(&instance->output_lock);
305 }
306}
307
308/**
309 * A public function which initializes input from the Serengeti console.
310 */
311sgcn_instance_t *sgcnin_init(void)
312{
313 sgcn_init();
314 return instance;
315}
316
317void sgcnin_wire(sgcn_instance_t *instance, indev_t *srlnin)
318{
319 ASSERT(instance);
320 ASSERT(srlnin);
321
322 instance->srlnin = srlnin;
323 thread_ready(instance->thread);
324
325 sysinfo_set_item_val("kbd", NULL, true);
326}
327
328/**
329 * A public function which initializes output to the Serengeti console.
330 */
331outdev_t *sgcnout_init(void)
332{
333 sgcn_init();
334 if (!instance)
335 return NULL;
336
337 outdev_t *sgcndev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
338 if (!sgcndev)
339 return NULL;
340
341 outdev_initialize("sgcndev", sgcndev, &sgcndev_ops);
342 sgcndev->data = instance;
343
344 if (!fb_exported) {
345 /*
346 * This is the necessary evil until the userspace driver is entirely
347 * self-sufficient.
348 */
349 sysinfo_set_item_val("fb.kind", NULL, 4);
350
351 fb_exported = true;
352 }
353
354 return sgcndev;
355}
356
357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.