Subversion Repositories HelenOS

Rev

Rev 3675 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3675 Rev 4377
Line 24... Line 24...
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup sparc64
29
/** @addtogroup sparc64
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <arch/drivers/kbd.h>
35
#include <arch/drivers/kbd.h>
36
#include <genarch/ofw/ofw_tree.h>
36
#include <genarch/ofw/ofw_tree.h>
-
 
37
 
-
 
38
#ifdef CONFIG_SUN_KBD
-
 
39
#include <genarch/kbrd/kbrd.h>
-
 
40
#endif
37
#ifdef CONFIG_Z8530
41
#ifdef CONFIG_Z8530
38
#include <genarch/kbd/z8530.h>
42
#include <genarch/drivers/z8530/z8530.h>
39
#endif
43
#endif
40
#ifdef CONFIG_NS16550
44
#ifdef CONFIG_NS16550
41
#include <genarch/kbd/ns16550.h>
45
#include <genarch/drivers/ns16550/ns16550.h>
42
#endif
46
#endif
-
 
47
 
43
#include <ddi/device.h>
48
#include <console/console.h>
44
#include <ddi/irq.h>
49
#include <ddi/irq.h>
45
#include <arch/mm/page.h>
50
#include <arch/mm/page.h>
46
#include <arch/types.h>
51
#include <arch/types.h>
47
#include <align.h>
52
#include <align.h>
48
#include <func.h>
53
#include <string.h>
49
#include <print.h>
54
#include <print.h>
-
 
55
#include <sysinfo/sysinfo.h>
50
 
56
 
51
kbd_type_t kbd_type = KBD_UNKNOWN;
57
#ifdef CONFIG_SUN_KBD
52
 
58
 
53
/** Initialize keyboard.
59
#ifdef CONFIG_Z8530
54
 *
60
 
55
 * Traverse OpenFirmware device tree in order to find necessary
-
 
56
 * info about the keyboard device.
-
 
57
 *
-
 
58
 * @param node Keyboard device node.
-
 
59
 */
-
 
60
void kbd_init(ofw_tree_node_t *node)
61
static bool kbd_z8530_init(ofw_tree_node_t *node)
61
{
62
{
-
 
63
    const char *name = ofw_tree_node_name(node);
-
 
64
   
-
 
65
    if (str_cmp(name, "zs") != 0)
62
    size_t offset;
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
   
63
    uintptr_t aligned_addr;
90
    uintptr_t pa;
-
 
91
    if (!ofw_fhc_apply_ranges(node->parent,
64
    ofw_tree_property_t *prop;
92
        ((ofw_fhc_reg_t *) prop->value), &pa)) {
-
 
93
        printf("z8530: Failed to determine address\n");
65
    const char *name;
94
        return false;
-
 
95
    }
-
 
96
   
-
 
97
    inr_t inr;
66
    cir_t cir;
98
    cir_t cir;
67
    void *cir_arg;
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;
68
   
105
    }
69
    name = ofw_tree_node_name(node);
-
 
70
   
106
   
71
    /*
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
72
     * Determine keyboard serial controller type.
111
     * underlying controller.
73
     */
112
     */
74
    if (strcmp(name, "zs") == 0)
113
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
75
        kbd_type = KBD_Z8530;
114
    size_t offset = pa - aligned_addr;
-
 
115
   
76
    else if (strcmp(name, "su") == 0)
116
    z8530_t *z8530 = (z8530_t *)
77
        kbd_type = KBD_NS16550;
117
        (hw_map(aligned_addr, offset + size) + offset);
78
   
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();
79
    if (kbd_type == KBD_UNKNOWN) {
122
        if (kbrd_instance) {
80
        printf("Unknown keyboard device.\n");
123
            indev_t *sink = stdin_wire();
-
 
124
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
-
 
125
            z8530_wire(z8530_instance, kbrd);
81
        return;
126
        }
82
    }
127
    }
83
   
128
   
84
    /*
129
    /*
-
 
130
     * This is the necessary evil until the userspace drivers are
85
     * Read 'interrupts' property.
131
     * entirely self-sufficient.
86
     */
132
     */
87
    uint32_t interrupts;
133
    sysinfo_set_item_val("kbd", NULL, true);
88
    prop = ofw_tree_getprop(node, "interrupts");
134
    sysinfo_set_item_val("kbd.inr", NULL, inr);
-
 
135
    sysinfo_set_item_val("kbd.address.kernel", NULL,
89
    if (!prop || !prop->value)
136
        (uintptr_t) z8530);
90
        panic("Can't find \"interrupts\" property.\n");
137
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
91
    interrupts = *((uint32_t *) prop->value);
138
    sysinfo_set_item_val("kbd.type.z8530", NULL, true);
-
 
139
   
-
 
140
    return true;
-
 
141
}
92
 
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
   
93
    /*
165
    /*
94
     * Read 'reg' property.
166
     * Read 'reg' property.
95
     */
167
     */
96
    prop = ofw_tree_getprop(node, "reg");
168
    prop = ofw_tree_getprop(node, "reg");
97
    if (!prop || !prop->value)
169
    if ((!prop) || (!prop->value)) {
98
        panic("Can't find \"reg\" property.\n");
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;
99
   
175
   
100
    uintptr_t pa;
176
    uintptr_t pa;
101
    size_t size;
177
    if (!ofw_ebus_apply_ranges(node->parent,
102
    inr_t inr;
178
        ((ofw_ebus_reg_t *) prop->value), &pa)) {
103
    devno_t devno = device_assign_devno();
179
        printf("ns16550: Failed to determine address\n");
-
 
180
        return false;
-
 
181
    }
104
   
182
   
105
    switch (kbd_type) {
-
 
106
    case KBD_Z8530:
-
 
107
        size = ((ofw_fhc_reg_t *) prop->value)->size;
-
 
108
        if (!ofw_fhc_apply_ranges(node->parent,
-
 
109
            ((ofw_fhc_reg_t *) prop->value), &pa)) {
-
 
110
            printf("Failed to determine keyboard address.\n");
-
 
111
            return;
183
    inr_t inr;
112
        }
-
 
113
        if (!ofw_fhc_map_interrupt(node->parent,
-
 
114
            ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
-
 
115
            &cir_arg)) {
-
 
116
            printf("Failed to determine keyboard interrupt.\n");
-
 
117
            return;
184
    cir_t cir;
118
        }
-
 
119
        break;
185
    void *cir_arg;
120
       
-
 
121
    case KBD_NS16550:
-
 
122
        size = ((ofw_ebus_reg_t *) prop->value)->size;
-
 
123
        if (!ofw_ebus_apply_ranges(node->parent,
-
 
124
            ((ofw_ebus_reg_t *) prop->value), &pa)) {
-
 
125
            printf("Failed to determine keyboard address.\n");
-
 
126
            return;
-
 
127
        }
-
 
128
        if (!ofw_ebus_map_interrupt(node->parent,
186
    if (!ofw_ebus_map_interrupt(node->parent,
129
            ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
187
        ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
130
            &cir_arg)) {
188
        &cir_arg)) {
131
            printf("Failed to determine keyboard interrupt.\n");
189
        printf("ns16550: Failed to determine interrupt\n");
132
            return;
190
        return false;
133
        };
-
 
134
        break;
-
 
135
 
-
 
136
    default:
-
 
137
        panic("Unexpected type.\n");
-
 
138
    }
191
    }
139
   
192
   
140
    /*
193
    /*
141
     * We need to pass aligned address to hw_map().
194
     * We need to pass aligned address to hw_map().
142
     * However, the physical keyboard address can
195
     * However, the physical keyboard address can
143
     * be pretty much unaligned, depending on the
196
     * be pretty much unaligned, depending on the
144
     * underlying controller.
197
     * underlying controller.
145
     */
198
     */
146
    aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
199
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
147
    offset = pa - aligned_addr;
200
    size_t offset = pa - aligned_addr;
-
 
201
   
-
 
202
    ns16550_t *ns16550 = (ns16550_t *)
148
    uintptr_t vaddr = hw_map(aligned_addr, offset + size) + offset;
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 */
149
 
230
 
150
    switch (kbd_type) {
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
{
151
#ifdef CONFIG_Z8530
241
#ifdef CONFIG_Z8530
152
    case KBD_Z8530:
-
 
153
        z8530_init(devno, vaddr, inr, cir, cir_arg);
242
    kbd_z8530_init(node);
154
        break;
-
 
155
#endif
243
#endif
-
 
244
   
156
#ifdef CONFIG_NS16550
245
#ifdef CONFIG_NS16550
157
    case KBD_NS16550:
246
    kbd_ns16550_init(node);
158
        ns16550_init(devno, (ioport_t)vaddr, inr, cir, cir_arg);
-
 
159
        break;
-
 
160
#endif
247
#endif
161
    default:
-
 
162
        printf("Kernel is not compiled with the necessary keyboard "
-
 
163
            "driver this machine requires.\n");
-
 
164
    }
-
 
165
}
248
}
166
 
249
 
-
 
250
#endif /* CONFIG_SUN_KBD */
-
 
251
 
167
/** @}
252
/** @}
168
 */
253
 */