Subversion Repositories HelenOS

Rev

Rev 4223 | Rev 4313 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 <string.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 *) (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 *) (sgcn_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.  
  104. /** starting address of SRAM, will be set by the init_sram_begin function */
  105. static uintptr_t sram_begin;
  106.  
  107. /**
  108.  * starting address of the SGCN buffer, will be set by the
  109.  * init_sgcn_buffer_begin function
  110.  */
  111. static uintptr_t sgcn_buffer_begin;
  112.  
  113. /* true iff the kernel driver should ignore pressed keys */
  114. static bool kbd_disabled;
  115.  
  116. /*
  117.  * Ensures that writing to the buffer and consequent update of the write pointer
  118.  * are together one atomic operation.
  119.  */
  120. SPINLOCK_INITIALIZE(sgcn_output_lock);
  121.  
  122. /*
  123.  * Prevents the input buffer read/write pointers from getting to inconsistent
  124.  * state.
  125.  */
  126. SPINLOCK_INITIALIZE(sgcn_input_lock);
  127.  
  128.  
  129. /* functions referenced from definitions of I/O operations structures */
  130. static void sgcn_putchar(outdev_t *, const wchar_t, bool);
  131.  
  132. /** SGCN output device operations */
  133. static outdev_operations_t sgcnout_ops = {
  134.     .write = sgcn_putchar
  135. };
  136.  
  137. /** SGCN input device operations */
  138. static indev_operations_t sgcnin_ops = {
  139.     .poll = NULL
  140. };
  141.  
  142. static indev_t sgcnin;      /**< SGCN input device. */
  143. static outdev_t sgcnout;    /**< SGCN output device. */
  144.  
  145. /**
  146.  * Set some sysinfo values (SRAM address and SRAM size).
  147.  */
  148. static void register_sram(uintptr_t sram_begin_physical)
  149. {
  150.     sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
  151.     sysinfo_set_item_val("sram.address.physical", NULL,
  152.         sram_begin_physical);
  153. }
  154.  
  155. /**
  156.  * Initializes the starting address of SRAM.
  157.  *
  158.  * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
  159.  * physical memory, where C is the value read from the "iosram-toc"
  160.  * property of the "/chosen" OBP node. The sram_begin variable will
  161.  * be set to the virtual address which maps to the SRAM physical
  162.  * address.
  163.  */
  164. static void init_sram_begin(void)
  165. {
  166.     ofw_tree_node_t *chosen;
  167.     ofw_tree_property_t *iosram_toc;
  168.     uintptr_t sram_begin_physical;
  169.  
  170.     chosen = ofw_tree_lookup("/chosen");
  171.     if (!chosen)
  172.         panic("Cannot find '/chosen'.");
  173.  
  174.     iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
  175.     if (!iosram_toc)
  176.         panic("Cannot find property 'iosram-toc'.");
  177.     if (!iosram_toc->value)
  178.         panic("Cannot find SRAM TOC.");
  179.  
  180.     sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
  181.         + *((uint32_t *) iosram_toc->value);
  182.     sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
  183.    
  184.     register_sram(sram_begin_physical);
  185. }
  186.  
  187. /**
  188.  * Initializes the starting address of the SGCN buffer.
  189.  *
  190.  * The offset of the SGCN buffer within SRAM is obtained from the
  191.  * SRAM table of contents. The table of contents contains
  192.  * information about several buffers, among which there is an OBP
  193.  * console buffer - this one will be used as the SGCN buffer.
  194.  *
  195.  * This function also writes the offset of the SGCN buffer within SRAM
  196.  * under the sram.buffer.offset sysinfo key.
  197.  */
  198. static void sgcn_buffer_begin_init(void)
  199. {
  200.     static bool initialized;
  201.    
  202.     if (initialized)
  203.         return;
  204.  
  205.     init_sram_begin();
  206.        
  207.     ASSERT(str_cmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
  208.    
  209.     /* lookup TOC entry with the correct key */
  210.     uint32_t i;
  211.     for (i = 0; i < MAX_TOC_ENTRIES; i++) {
  212.         if (str_cmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
  213.             break;
  214.     }
  215.     ASSERT(i < MAX_TOC_ENTRIES);
  216.    
  217.     sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
  218.    
  219.     sysinfo_set_item_val("sram.buffer.offset", NULL,
  220.         SRAM_TOC->keys[i].offset);
  221.    
  222.     initialized = true;
  223. }
  224.  
  225. /**
  226.  * Writes a single character to the SGCN (circular) output buffer
  227.  * and updates the output write pointer so that SGCN gets to know
  228.  * that the character has been written.
  229.  */
  230. static void sgcn_do_putchar(const char c)
  231. {
  232.     uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
  233.     uint32_t end = SGCN_BUFFER_HEADER->out_end;
  234.     uint32_t size = end - begin;
  235.    
  236.     /* we need pointers to volatile variables */
  237.     volatile char *buf_ptr = (volatile char *)
  238.         SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
  239.     volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
  240.     volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
  241.  
  242.     /*
  243.      * Write the character and increment the write pointer modulo the
  244.      * output buffer size. Note that if we are to rewrite a character
  245.      * which has not been read by the SGCN controller yet (i.e. the output
  246.      * buffer is full), we need to wait until the controller reads some more
  247.      * characters. We wait actively, which means that all threads waiting
  248.      * for the lock are blocked. However, this situation is
  249.      *   1) rare - the output buffer is big, so filling the whole
  250.      *             output buffer is improbable
  251.      *   2) short-lasting - it will take the controller only a fraction
  252.      *             of millisecond to pick the unread characters up
  253.      *   3) not serious - the blocked threads are those that print something
  254.      *             to user console, which is not a time-critical operation
  255.      */
  256.     uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
  257.     while (*out_rdptr_ptr == new_wrptr)
  258.         ;
  259.     *buf_ptr = c;
  260.     *out_wrptr_ptr = new_wrptr;
  261. }
  262.  
  263. /**
  264.  * SGCN output operation. Prints a single character to the SGCN. Newline
  265.  * character is converted to CRLF.
  266.  */
  267. static void sgcn_putchar(outdev_t *od, const wchar_t ch, bool silent)
  268. {
  269.     if (!silent) {
  270.         spinlock_lock(&sgcn_output_lock);
  271.        
  272.         if (ascii_check(ch)) {
  273.             if (ch == '\n')
  274.                 sgcn_do_putchar('\r');
  275.             sgcn_do_putchar(ch);
  276.         } else
  277.             sgcn_do_putchar(U_SPECIAL);
  278.        
  279.         spinlock_unlock(&sgcn_output_lock);
  280.     }
  281. }
  282.  
  283. /**
  284.  * Grabs the input for kernel.
  285.  */
  286. void sgcn_grab(void)
  287. {
  288.     kbd_disabled = true;
  289. }
  290.  
  291. /**
  292.  * Releases the input so that userspace can use it.
  293.  */
  294. void sgcn_release(void)
  295. {
  296.     kbd_disabled = true;
  297. }
  298.  
  299. /**
  300.  * Function regularly called by the keyboard polling thread. Finds out whether
  301.  * there are some unread characters in the input queue. If so, it picks them up
  302.  * and sends them to the upper layers of HelenOS.
  303.  */
  304. static void sgcn_poll()
  305. {
  306.     uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
  307.     uint32_t end = SGCN_BUFFER_HEADER->in_end;
  308.     uint32_t size = end - begin;
  309.  
  310.     if (kbd_disabled)
  311.         return;
  312.  
  313.     spinlock_lock(&sgcn_input_lock);
  314.    
  315.     /* we need pointers to volatile variables */
  316.     volatile char *buf_ptr = (volatile char *)
  317.         SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
  318.     volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
  319.     volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
  320.    
  321.     while (*in_rdptr_ptr != *in_wrptr_ptr) {
  322.        
  323.         buf_ptr = (volatile char *)
  324.             SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
  325.         char c = *buf_ptr;
  326.         *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
  327.            
  328.         indev_push_character(&sgcnin, c);  
  329.     }  
  330.  
  331.     spinlock_unlock(&sgcn_input_lock);
  332. }
  333.  
  334. /**
  335.  * Polling thread function.
  336.  */
  337. static void kkbdpoll(void *arg) {
  338.     while (1) {
  339.         if (!silent) {
  340.             sgcn_poll();
  341.         }
  342.         thread_usleep(POLL_INTERVAL);
  343.     }
  344. }
  345.  
  346. /**
  347.  * A public function which initializes input from the Serengeti console.
  348.  */
  349. indev_t *sgcnin_init(void)
  350. {
  351.     sgcn_buffer_begin_init();
  352.  
  353.     sysinfo_set_item_val("kbd", NULL, true);
  354.  
  355.     thread_t *t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true);
  356.     if (!t)
  357.         panic("Cannot create kkbdpoll.");
  358.     thread_ready(t);
  359.    
  360.     indev_initialize("sgcnin", &sgcnin, &sgcnin_ops);
  361.  
  362.     return &sgcnin;
  363. }
  364.  
  365. /**
  366.  * A public function which initializes output to the Serengeti console.
  367.  */
  368. void sgcnout_init(void)
  369. {
  370.     sgcn_buffer_begin_init();
  371.  
  372.     sysinfo_set_item_val("fb.kind", NULL, 4);
  373.  
  374.     outdev_initialize("sgcnout", &sgcnout, &sgcnout_ops);  
  375.     stdout = &sgcnout;
  376. }
  377.  
  378. /** @}
  379.  */
  380.