Subversion Repositories HelenOS

Rev

Rev 4347 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Jakub Jermar
  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. /** @file
  33.  */
  34.  
  35. #include <arch/drivers/kbd.h>
  36. #include <genarch/ofw/ofw_tree.h>
  37.  
  38. #ifdef CONFIG_SUN_KBD
  39. #include <genarch/kbrd/kbrd.h>
  40. #endif
  41. #ifdef CONFIG_Z8530
  42. #include <genarch/drivers/z8530/z8530.h>
  43. #endif
  44. #ifdef CONFIG_NS16550
  45. #include <genarch/drivers/ns16550/ns16550.h>
  46. #endif
  47.  
  48. #include <console/console.h>
  49. #include <ddi/irq.h>
  50. #include <arch/mm/page.h>
  51. #include <arch/types.h>
  52. #include <align.h>
  53. #include <string.h>
  54. #include <print.h>
  55. #include <sysinfo/sysinfo.h>
  56.  
  57. #ifdef CONFIG_SUN_KBD
  58.  
  59. #ifdef CONFIG_Z8530
  60.  
  61. static bool kbd_z8530_init(ofw_tree_node_t *node)
  62. {
  63.     const char *name = ofw_tree_node_name(node);
  64.    
  65.     if (str_cmp(name, "zs") != 0)
  66.         return false;
  67.    
  68.     /*
  69.      * Read 'interrupts' property.
  70.      */
  71.     ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
  72.     if ((!prop) || (!prop->value)) {
  73.         printf("z8530: Unable to find interrupts property\n");
  74.         return false;
  75.     }
  76.    
  77.     uint32_t interrupts = *((uint32_t *) prop->value);
  78.    
  79.     /*
  80.      * Read 'reg' property.
  81.      */
  82.     prop = ofw_tree_getprop(node, "reg");
  83.     if ((!prop) || (!prop->value)) {
  84.         printf("z8530: Unable to find reg property\n");
  85.         return false;
  86.     }
  87.    
  88.     size_t size = ((ofw_fhc_reg_t *) prop->value)->size;
  89.    
  90.     uintptr_t pa;
  91.     if (!ofw_fhc_apply_ranges(node->parent,
  92.         ((ofw_fhc_reg_t *) prop->value), &pa)) {
  93.         printf("z8530: Failed to determine address\n");
  94.         return false;
  95.     }
  96.    
  97.     inr_t inr;
  98.     cir_t cir;
  99.     void *cir_arg;
  100.     if (!ofw_fhc_map_interrupt(node->parent,
  101.         ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
  102.         &cir_arg)) {
  103.         printf("z8530: Failed to determine interrupt\n");
  104.         return false;
  105.     }
  106.    
  107.     /*
  108.      * We need to pass aligned address to hw_map().
  109.      * However, the physical keyboard address can
  110.      * be pretty much unaligned, depending on the
  111.      * underlying controller.
  112.      */
  113.     uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
  114.     size_t offset = pa - aligned_addr;
  115.    
  116.     z8530_t *z8530 = (z8530_t *)
  117.         (hw_map(aligned_addr, offset + size) + offset);
  118.    
  119.     z8530_instance_t *z8530_instance = z8530_init(z8530, inr, cir, cir_arg);
  120.     if (z8530_instance) {
  121.         kbrd_instance_t *kbrd_instance = kbrd_init();
  122.         if (kbrd_instance) {
  123.             indev_t *sink = stdin_wire();
  124.             indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
  125.             z8530_wire(z8530_instance, kbrd);
  126.         }
  127.     }
  128.    
  129.     /*
  130.      * This is the necessary evil until the userspace drivers are
  131.      * entirely self-sufficient.
  132.      */
  133.     sysinfo_set_item_val("kbd", NULL, true);
  134.     sysinfo_set_item_val("kbd.inr", NULL, inr);
  135.     sysinfo_set_item_val("kbd.address.kernel", NULL,
  136.         (uintptr_t) z8530);
  137.     sysinfo_set_item_val("kbd.address.physical", NULL, pa);
  138.     sysinfo_set_item_val("kbd.type.z8530", NULL, true);
  139.    
  140.     return true;
  141. }
  142.  
  143. #endif /* CONFIG_Z8530 */
  144.  
  145. #ifdef CONFIG_NS16550
  146.  
  147. static bool kbd_ns16550_init(ofw_tree_node_t *node)
  148. {
  149.     const char *name = ofw_tree_node_name(node);
  150.    
  151.     if (str_cmp(name, "su") != 0)
  152.         return false;
  153.    
  154.     /*
  155.      * Read 'interrupts' property.
  156.      */
  157.     ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
  158.     if ((!prop) || (!prop->value)) {
  159.         printf("ns16550: Unable to find interrupts property\n");
  160.         return false;
  161.     }
  162.    
  163.     uint32_t interrupts = *((uint32_t *) prop->value);
  164.    
  165.     /*
  166.      * Read 'reg' property.
  167.      */
  168.     prop = ofw_tree_getprop(node, "reg");
  169.     if ((!prop) || (!prop->value)) {
  170.         printf("ns16550: Unable to find reg property\n");
  171.         return false;
  172.     }
  173.    
  174.     size_t size = ((ofw_ebus_reg_t *) prop->value)->size;
  175.    
  176.     uintptr_t pa;
  177.     if (!ofw_ebus_apply_ranges(node->parent,
  178.         ((ofw_ebus_reg_t *) prop->value), &pa)) {
  179.         printf("ns16550: Failed to determine address\n");
  180.         return false;
  181.     }
  182.    
  183.     inr_t inr;
  184.     cir_t cir;
  185.     void *cir_arg;
  186.     if (!ofw_ebus_map_interrupt(node->parent,
  187.         ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
  188.         &cir_arg)) {
  189.         printf("ns16550: Failed to determine interrupt\n");
  190.         return false;
  191.     }
  192.    
  193.     /*
  194.      * We need to pass aligned address to hw_map().
  195.      * However, the physical keyboard address can
  196.      * be pretty much unaligned, depending on the
  197.      * underlying controller.
  198.      */
  199.     uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
  200.     size_t offset = pa - aligned_addr;
  201.    
  202.     ns16550_t *ns16550 = (ns16550_t *)
  203.        (hw_map(aligned_addr, offset + size) + offset);
  204.    
  205.     ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir, cir_arg);
  206.     if (ns16550_instance) {
  207.         kbrd_instance_t *kbrd_instance = kbrd_init();
  208.         if (kbrd_instance) {
  209.             indev_t *sink = stdin_wire();
  210.             indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
  211.             ns16550_wire(ns16550_instance, kbrd);
  212.         }
  213.     }
  214.    
  215.     /*
  216.      * This is the necessary evil until the userspace drivers are
  217.      * entirely self-sufficient.
  218.      */
  219.     sysinfo_set_item_val("kbd", NULL, true);
  220.     sysinfo_set_item_val("kbd.inr", NULL, inr);
  221.     sysinfo_set_item_val("kbd.address.kernel", NULL,
  222.         (uintptr_t) ns16550);
  223.     sysinfo_set_item_val("kbd.address.physical", NULL, pa);
  224.     sysinfo_set_item_val("kbd.type.ns16550", NULL, true);
  225.    
  226.     return true;
  227. }
  228.  
  229. #endif /* CONFIG_NS16550 */
  230.  
  231. /** Initialize keyboard.
  232.  *
  233.  * Traverse OpenFirmware device tree in order to find necessary
  234.  * info about the keyboard device.
  235.  *
  236.  * @param node Keyboard device node.
  237.  *
  238.  */
  239. void kbd_init(ofw_tree_node_t *node)
  240. {
  241. #ifdef CONFIG_Z8530
  242.     kbd_z8530_init(node);
  243. #endif
  244.    
  245. #ifdef CONFIG_NS16550
  246.     kbd_ns16550_init(node);
  247. #endif
  248. }
  249.  
  250. #endif /* CONFIG_SUN_KBD */
  251.  
  252. /** @}
  253.  */
  254.