Subversion Repositories HelenOS

Rev

Rev 3863 | 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   Niagara input/output driver based on hypervisor calls.
  35.  */
  36.  
  37. #include <arch/drivers/niagara.h>
  38. #include <console/chardev.h>
  39. #include <console/console.h>
  40. #include <ddi/ddi.h>
  41. #include <ddi/device.h>
  42. #include <arch/asm.h>
  43. #include <arch/drivers/kbd.h>
  44. #include <arch/sun4v/hypercall.h>
  45. #include <sysinfo/sysinfo.h>
  46. #include <ipc/irq.h>
  47.  
  48. /**
  49.  * The driver is polling based, but in order to notify the userspace
  50.  * of a key being pressed, we need to supply the interface with some
  51.  * interrupt number. The interrupt number can be arbitrary as it it
  52.  * will never be used for identifying HW interrupts, but only in
  53.  * notifying the userspace.
  54.  */
  55. #define FICTIONAL_INR       1
  56.  
  57. /* functions referenced from definitions of I/O operations structures */
  58. static void niagara_putchar(chardev_t *, const char);
  59. static void niagara_noop(chardev_t *);
  60. static char niagara_read(chardev_t *);
  61.  
  62. /** character device operations */
  63. static chardev_operations_t niagara_ops = {
  64.     .write = niagara_putchar,
  65.     .suspend = niagara_noop,
  66.     .resume = niagara_noop,
  67.     .read = niagara_read
  68. };
  69.  
  70. /*
  71.  * The driver uses hypercalls to print characters to the console. Since the
  72.  * hypercall cannot be performed from the userspace, we do this:
  73.  * The kernel "little brother" driver (which will be present no matter what the
  74.  * DDI architecture is - as we need the kernel part for the kconsole)
  75.  * defines a shared buffer. Kernel walks through the buffer (in the same thread
  76.  * which is used for polling the keyboard) and prints any pending characters
  77.  * to the console (using hypercalls). The userspace fb server maps this shared
  78.  * buffer to its address space and output operation it does is performed using
  79.  * the mapped buffer. The shared buffer definition follows.
  80.  */
  81. #define OUTPUT_BUFFER_SIZE  ((PAGE_SIZE) - 2 * 8)
  82. static volatile struct {
  83.     uint64_t read_ptr;
  84.     uint64_t write_ptr;
  85.     char data[OUTPUT_BUFFER_SIZE];
  86. }
  87.     __attribute__ ((packed))
  88.     __attribute__ ((aligned(PAGE_SIZE)))
  89.     output_buffer;
  90.  
  91. /** Niagara character device */
  92. chardev_t niagara_io;
  93.  
  94. /**
  95.  * Niagara IRQ structure. So far used only for notifying the userspace of the
  96.  * key being pressed, not for kernel being informed about keyboard interrupts.
  97.  */
  98. static irq_t niagara_irq;
  99.  
  100. /** defined in drivers/kbd.c */
  101. extern kbd_type_t kbd_type;
  102.  
  103. /**
  104.  * The character read will be stored here until the (notified) uspace
  105.  * driver picks it up.
  106.  */
  107. static char read_char;
  108.  
  109. /**
  110.  * The driver works in polled mode, so no interrupt should be handled by it.
  111.  */
  112. static irq_ownership_t niagara_claim(void)
  113. {
  114.     return IRQ_DECLINE;
  115. }
  116.  
  117. /**
  118.  * The driver works in polled mode, so no interrupt should be handled by it.
  119.  */
  120. static void niagara_irq_handler(irq_t *irq, void *arg, ...)
  121. {
  122.     panic("Not yet implemented, SGCN works in polled mode.\n");
  123. }
  124.  
  125. /** Writes a single character to the standard output. */
  126. static inline void do_putchar(const char c) {
  127.     /* repeat until the buffer is non-full */
  128.     while (__hypercall_fast1(CONS_PUTCHAR, c) == EWOULDBLOCK)
  129.         ;
  130. }
  131.  
  132. /** Writes a single character to the standard output. */
  133. static void niagara_putchar(struct chardev * cd, const char c)
  134. {
  135.     do_putchar(c);
  136.     if (c == '\n')
  137.         do_putchar('\r');
  138. }
  139.  
  140. /**
  141.  * Grabs the input for kernel.
  142.  */
  143. void niagara_grab(void)
  144. {
  145.     ipl_t ipl = interrupts_disable();
  146.     spinlock_lock(&niagara_irq.lock);
  147.     niagara_irq.notif_cfg.notify = false;
  148.     spinlock_unlock(&niagara_irq.lock);
  149.     interrupts_restore(ipl);
  150. }
  151.  
  152. /**
  153.  * Releases the input so that userspace can use it.
  154.  */
  155. void niagara_release(void)
  156. {
  157.     ipl_t ipl = interrupts_disable();
  158.     spinlock_lock(&niagara_irq.lock);
  159.     if (niagara_irq.notif_cfg.answerbox)
  160.         niagara_irq.notif_cfg.notify = true;
  161.     spinlock_unlock(&niagara_irq.lock);
  162.     interrupts_restore(ipl);
  163. }
  164.  
  165. /**
  166.  * Default suspend/resume operation for the input device.
  167.  */
  168. static void niagara_noop(chardev_t *d)
  169. {
  170. }
  171.  
  172. /**
  173.  * Called when actively reading the character.
  174.  */
  175. static char niagara_read(chardev_t *d)
  176. {
  177.     uint64_t c;
  178.  
  179.     if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) {
  180.         return (char) c;
  181.     }
  182.  
  183.     return '\0';
  184. }
  185.  
  186. /**
  187.  * Returns the character last read. This function is called from the
  188.  * pseudocode - the character returned by this function is passed to
  189.  * the userspace keyboard driver.
  190.  */
  191. char niagara_getc(void) {
  192.     return read_char;
  193. }
  194.  
  195. /**
  196.  * Function regularly called by the keyboard polling thread. Asks the
  197.  * hypervisor whether there is any unread character. If so, it picks it up
  198.  * and sends it to the upper layers of HelenOS.
  199.  */
  200. void niagara_poll(void)
  201. {
  202.     while (output_buffer.read_ptr != output_buffer.write_ptr) {
  203.         do_putchar(output_buffer.data[output_buffer.read_ptr]);
  204.         output_buffer.read_ptr =
  205.             ((output_buffer.read_ptr) + 1) % OUTPUT_BUFFER_SIZE;
  206.     }
  207.  
  208.     uint64_t c;
  209.  
  210.     if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) {
  211.         ipl_t ipl = interrupts_disable();
  212.         spinlock_lock(&niagara_irq.lock);
  213.  
  214.         if (niagara_irq.notif_cfg.notify &&
  215.                 niagara_irq.notif_cfg.answerbox) {
  216.             /*
  217.              * remember the character, uspace will pick it
  218.              * up using pseudocode
  219.              */
  220.             read_char = (char) c;
  221.             ipc_irq_send_notif(&niagara_irq);
  222.             spinlock_unlock(&niagara_irq.lock);
  223.             interrupts_restore(ipl);
  224.             return;
  225.         } else {
  226.             spinlock_unlock(&niagara_irq.lock);
  227.             interrupts_restore(ipl);   
  228.  
  229.             chardev_push_character(&niagara_io, c);
  230.             if (c == '\r')
  231.                 chardev_push_character(&niagara_io, '\n');
  232.         }
  233.     }
  234.  
  235. }
  236.  
  237. /**
  238.  * Initializes the input/output subsystem so that the Niagara standard
  239.  * input/output is used.
  240.  */
  241. void niagara_init(void)
  242. {
  243.     kbd_type = KBD_SUN4V;
  244.  
  245.     devno_t devno = device_assign_devno();
  246.     irq_initialize(&niagara_irq);
  247.     niagara_irq.devno = devno;
  248.     niagara_irq.inr = FICTIONAL_INR;
  249.     niagara_irq.claim = niagara_claim;
  250.     niagara_irq.handler = niagara_irq_handler;
  251.     irq_register(&niagara_irq);
  252.    
  253.     sysinfo_set_item_val("kbd", NULL, true);
  254.     sysinfo_set_item_val("kbd.type", NULL, KBD_SUN4V);
  255.     sysinfo_set_item_val("kbd.devno", NULL, devno);
  256.     sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
  257.     sysinfo_set_item_val("fb.kind", NULL, 5);
  258.  
  259.     /*
  260.      * Set sysinfos and pareas so that the userspace counterpart of the
  261.      * niagara fb driver can communicate with kernel using a shared buffer.
  262.      */
  263.     output_buffer.read_ptr = 0;
  264.     output_buffer.write_ptr = 0;
  265.     sysinfo_set_item_val("niagara.outbuf.address", NULL,
  266.         KA2PA(&output_buffer));
  267.     sysinfo_set_item_val("niagara.outbuf.size", NULL,
  268.         PAGE_SIZE);
  269.     sysinfo_set_item_val("niagara.outbuf.datasize", NULL,
  270.         OUTPUT_BUFFER_SIZE);
  271.     static parea_t outbuf_parea;
  272.     outbuf_parea.pbase = (uintptr_t) (KA2PA(&output_buffer));
  273.     outbuf_parea.vbase = (uintptr_t) (&output_buffer);
  274.     outbuf_parea.frames = 1;
  275.     outbuf_parea.cacheable = false;
  276.     ddi_parea_register(&outbuf_parea);
  277.  
  278.     chardev_initialize("niagara_io", &niagara_io, &niagara_ops);
  279.     stdin = &niagara_io;
  280.     stdout = &niagara_io;
  281. }
  282.  
  283. /** @}
  284.  */
  285.