Subversion Repositories HelenOS

Rev

Rev 4311 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4311 Rev 4687
1
/*
1
/*
2
 * Copyright (c) 2006 Jakub Jermar
2
 * Copyright (c) 2006 Jakub Jermar
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
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
 
37
 
38
#ifdef CONFIG_SUN_KBD
38
#ifdef CONFIG_SUN_KBD
39
#include <genarch/kbrd/kbrd.h>
39
#include <genarch/kbrd/kbrd.h>
40
#endif
40
#endif
41
#ifdef CONFIG_Z8530
41
#ifdef CONFIG_Z8530
42
#include <genarch/drivers/z8530/z8530.h>
42
#include <genarch/drivers/z8530/z8530.h>
43
#endif
43
#endif
44
#ifdef CONFIG_NS16550
44
#ifdef CONFIG_NS16550
45
#include <genarch/drivers/ns16550/ns16550.h>
45
#include <genarch/drivers/ns16550/ns16550.h>
46
#endif
46
#endif
47
 
47
 
48
#include <console/console.h>
48
#include <console/console.h>
49
#include <ddi/irq.h>
49
#include <ddi/irq.h>
50
#include <arch/mm/page.h>
50
#include <arch/mm/page.h>
51
#include <arch/types.h>
51
#include <arch/types.h>
52
#include <align.h>
52
#include <align.h>
53
#include <string.h>
53
#include <string.h>
54
#include <print.h>
54
#include <print.h>
55
#include <sysinfo/sysinfo.h>
55
#include <sysinfo/sysinfo.h>
56
 
56
 
57
#ifdef CONFIG_SUN_KBD
57
#ifdef CONFIG_SUN_KBD
58
 
58
 
59
#ifdef CONFIG_Z8530
59
#ifdef CONFIG_Z8530
60
 
60
 
61
static bool kbd_z8530_init(ofw_tree_node_t *node)
61
static bool kbd_z8530_init(ofw_tree_node_t *node)
62
{
62
{
63
    const char *name = ofw_tree_node_name(node);
63
    const char *name = ofw_tree_node_name(node);
64
   
64
   
65
    if (str_cmp(name, "zs") != 0)
65
    if (str_cmp(name, "zs") != 0)
66
        return false;
66
        return false;
67
   
67
   
68
    /*
68
    /*
69
     * Read 'interrupts' property.
69
     * Read 'interrupts' property.
70
     */
70
     */
71
    ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
71
    ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
72
    if ((!prop) || (!prop->value)) {
72
    if ((!prop) || (!prop->value)) {
73
        printf("z8530: Unable to find interrupts property\n");
73
        printf("z8530: Unable to find interrupts property\n");
74
        return false;
74
        return false;
75
    }
75
    }
76
   
76
   
77
    uint32_t interrupts = *((uint32_t *) prop->value);
77
    uint32_t interrupts = *((uint32_t *) prop->value);
78
   
78
   
79
    /*
79
    /*
80
     * Read 'reg' property.
80
     * Read 'reg' property.
81
     */
81
     */
82
    prop = ofw_tree_getprop(node, "reg");
82
    prop = ofw_tree_getprop(node, "reg");
83
    if ((!prop) || (!prop->value)) {
83
    if ((!prop) || (!prop->value)) {
84
        printf("z8530: Unable to find reg property\n");
84
        printf("z8530: Unable to find reg property\n");
85
        return false;
85
        return false;
86
    }
86
    }
87
   
87
   
88
    size_t size = ((ofw_fhc_reg_t *) prop->value)->size;
88
    size_t size = ((ofw_fhc_reg_t *) prop->value)->size;
89
   
89
   
90
    uintptr_t pa;
90
    uintptr_t pa;
91
    if (!ofw_fhc_apply_ranges(node->parent,
91
    if (!ofw_fhc_apply_ranges(node->parent,
92
        ((ofw_fhc_reg_t *) prop->value), &pa)) {
92
        ((ofw_fhc_reg_t *) prop->value), &pa)) {
93
        printf("z8530: Failed to determine address\n");
93
        printf("z8530: Failed to determine address\n");
94
        return false;
94
        return false;
95
    }
95
    }
96
   
96
   
97
    inr_t inr;
97
    inr_t inr;
98
    cir_t cir;
98
    cir_t cir;
99
    void *cir_arg;
99
    void *cir_arg;
100
    if (!ofw_fhc_map_interrupt(node->parent,
100
    if (!ofw_fhc_map_interrupt(node->parent,
101
        ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
101
        ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
102
        &cir_arg)) {
102
        &cir_arg)) {
103
        printf("z8530: Failed to determine interrupt\n");
103
        printf("z8530: Failed to determine interrupt\n");
104
        return false;
104
        return false;
105
    }
105
    }
106
   
106
   
107
    /*
107
    /*
108
     * We need to pass aligned address to hw_map().
108
     * We need to pass aligned address to hw_map().
109
     * However, the physical keyboard address can
109
     * However, the physical keyboard address can
110
     * be pretty much unaligned, depending on the
110
     * be pretty much unaligned, depending on the
111
     * underlying controller.
111
     * underlying controller.
112
     */
112
     */
113
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
113
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
114
    size_t offset = pa - aligned_addr;
114
    size_t offset = pa - aligned_addr;
115
   
115
   
116
    z8530_t *z8530 = (z8530_t *)
116
    z8530_t *z8530 = (z8530_t *)
117
        (hw_map(aligned_addr, offset + size) + offset);
117
        (hw_map(aligned_addr, offset + size) + offset);
118
   
118
   
119
    z8530_instance_t *z8530_instance = z8530_init(z8530, inr, cir, cir_arg);
119
    z8530_instance_t *z8530_instance = z8530_init(z8530, inr, cir, cir_arg);
120
    if (z8530_instance) {
120
    if (z8530_instance) {
121
        kbrd_instance_t *kbrd_instance = kbrd_init();
121
        kbrd_instance_t *kbrd_instance = kbrd_init();
122
        if (kbrd_instance) {
122
        if (kbrd_instance) {
123
            indev_t *sink = stdin_wire();
123
            indev_t *sink = stdin_wire();
124
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
124
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
125
            z8530_wire(z8530_instance, kbrd);
125
            z8530_wire(z8530_instance, kbrd);
126
        }
126
        }
127
    }
127
    }
128
   
128
   
129
    /*
129
    /*
130
     * This is the necessary evil until the userspace drivers are
130
     * This is the necessary evil until the userspace drivers are
131
     * entirely self-sufficient.
131
     * entirely self-sufficient.
132
     */
132
     */
133
    sysinfo_set_item_val("kbd", NULL, true);
133
    sysinfo_set_item_val("kbd", NULL, true);
134
    sysinfo_set_item_val("kbd.inr", NULL, inr);
134
    sysinfo_set_item_val("kbd.inr", NULL, inr);
135
    sysinfo_set_item_val("kbd.address.kernel", NULL,
135
    sysinfo_set_item_val("kbd.address.kernel", NULL,
136
        (uintptr_t) z8530);
136
        (uintptr_t) z8530);
137
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
137
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
138
    sysinfo_set_item_val("kbd.type.z8530", NULL, true);
138
    sysinfo_set_item_val("kbd.type.z8530", NULL, true);
139
   
139
   
140
    return true;
140
    return true;
141
}
141
}
142
 
142
 
143
#endif /* CONFIG_Z8530 */
143
#endif /* CONFIG_Z8530 */
144
 
144
 
145
#ifdef CONFIG_NS16550
145
#ifdef CONFIG_NS16550
146
 
146
 
147
static bool kbd_ns16550_init(ofw_tree_node_t *node)
147
static bool kbd_ns16550_init(ofw_tree_node_t *node)
148
{
148
{
149
    const char *name = ofw_tree_node_name(node);
149
    const char *name = ofw_tree_node_name(node);
150
   
150
   
151
    if (str_cmp(name, "su") != 0)
151
    if (str_cmp(name, "su") != 0)
152
        return false;
152
        return false;
153
   
153
   
154
    /*
154
    /*
155
     * Read 'interrupts' property.
155
     * Read 'interrupts' property.
156
     */
156
     */
157
    ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
157
    ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
158
    if ((!prop) || (!prop->value)) {
158
    if ((!prop) || (!prop->value)) {
159
        printf("ns16550: Unable to find interrupts property\n");
159
        printf("ns16550: Unable to find interrupts property\n");
160
        return false;
160
        return false;
161
    }
161
    }
162
   
162
   
163
    uint32_t interrupts = *((uint32_t *) prop->value);
163
    uint32_t interrupts = *((uint32_t *) prop->value);
164
   
164
   
165
    /*
165
    /*
166
     * Read 'reg' property.
166
     * Read 'reg' property.
167
     */
167
     */
168
    prop = ofw_tree_getprop(node, "reg");
168
    prop = ofw_tree_getprop(node, "reg");
169
    if ((!prop) || (!prop->value)) {
169
    if ((!prop) || (!prop->value)) {
170
        printf("ns16550: Unable to find reg property\n");
170
        printf("ns16550: Unable to find reg property\n");
171
        return false;
171
        return false;
172
    }
172
    }
173
   
173
   
174
    size_t size = ((ofw_ebus_reg_t *) prop->value)->size;
174
    size_t size = ((ofw_ebus_reg_t *) prop->value)->size;
175
   
175
   
176
    uintptr_t pa;
176
    uintptr_t pa;
177
    if (!ofw_ebus_apply_ranges(node->parent,
177
    if (!ofw_ebus_apply_ranges(node->parent,
178
        ((ofw_ebus_reg_t *) prop->value), &pa)) {
178
        ((ofw_ebus_reg_t *) prop->value), &pa)) {
179
        printf("ns16550: Failed to determine address\n");
179
        printf("ns16550: Failed to determine address\n");
180
        return false;
180
        return false;
181
    }
181
    }
182
   
182
   
183
    inr_t inr;
183
    inr_t inr;
184
    cir_t cir;
184
    cir_t cir;
185
    void *cir_arg;
185
    void *cir_arg;
186
    if (!ofw_ebus_map_interrupt(node->parent,
186
    if (!ofw_ebus_map_interrupt(node->parent,
187
        ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
187
        ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
188
        &cir_arg)) {
188
        &cir_arg)) {
189
        printf("ns16550: Failed to determine interrupt\n");
189
        printf("ns16550: Failed to determine interrupt\n");
190
        return false;
190
        return false;
191
    }
191
    }
192
   
192
   
193
    /*
193
    /*
194
     * We need to pass aligned address to hw_map().
194
     * We need to pass aligned address to hw_map().
195
     * However, the physical keyboard address can
195
     * However, the physical keyboard address can
196
     * be pretty much unaligned, depending on the
196
     * be pretty much unaligned, depending on the
197
     * underlying controller.
197
     * underlying controller.
198
     */
198
     */
199
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
199
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
200
    size_t offset = pa - aligned_addr;
200
    size_t offset = pa - aligned_addr;
201
   
201
   
202
    ns16550_t *ns16550 = (ns16550_t *)
202
    ns16550_t *ns16550 = (ns16550_t *)
203
       (hw_map(aligned_addr, offset + size) + offset);
203
       (hw_map(aligned_addr, offset + size) + offset);
204
   
204
   
205
    ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir, cir_arg);
205
    ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir, cir_arg);
206
    if (ns16550_instance) {
206
    if (ns16550_instance) {
207
        kbrd_instance_t *kbrd_instance = kbrd_init();
207
        kbrd_instance_t *kbrd_instance = kbrd_init();
208
        if (kbrd_instance) {
208
        if (kbrd_instance) {
209
            indev_t *sink = stdin_wire();
209
            indev_t *sink = stdin_wire();
210
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
210
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
211
            ns16550_wire(ns16550_instance, kbrd);
211
            ns16550_wire(ns16550_instance, kbrd);
212
        }
212
        }
213
    }
213
    }
214
   
214
   
215
    /*
215
    /*
216
     * This is the necessary evil until the userspace drivers are
216
     * This is the necessary evil until the userspace drivers are
217
     * entirely self-sufficient.
217
     * entirely self-sufficient.
218
     */
218
     */
219
    sysinfo_set_item_val("kbd", NULL, true);
219
    sysinfo_set_item_val("kbd", NULL, true);
220
    sysinfo_set_item_val("kbd.inr", NULL, inr);
220
    sysinfo_set_item_val("kbd.inr", NULL, inr);
221
    sysinfo_set_item_val("kbd.address.kernel", NULL,
221
    sysinfo_set_item_val("kbd.address.kernel", NULL,
222
        (uintptr_t) ns16550);
222
        (uintptr_t) ns16550);
223
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
223
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
224
    sysinfo_set_item_val("kbd.type.ns16550", NULL, true);
224
    sysinfo_set_item_val("kbd.type.ns16550", NULL, true);
225
   
225
   
226
    return true;
226
    return true;
227
}
227
}
228
 
228
 
229
#endif /* CONFIG_NS16550 */
229
#endif /* CONFIG_NS16550 */
230
 
230
 
231
/** Initialize keyboard.
231
/** Initialize keyboard.
232
 *
232
 *
233
 * Traverse OpenFirmware device tree in order to find necessary
233
 * Traverse OpenFirmware device tree in order to find necessary
234
 * info about the keyboard device.
234
 * info about the keyboard device.
235
 *
235
 *
236
 * @param node Keyboard device node.
236
 * @param node Keyboard device node.
237
 *
237
 *
238
 */
238
 */
239
void kbd_init(ofw_tree_node_t *node)
239
void kbd_init(ofw_tree_node_t *node)
240
{
240
{
241
#ifdef CONFIG_Z8530
241
#ifdef CONFIG_Z8530
242
    kbd_z8530_init(node);
242
    kbd_z8530_init(node);
243
#endif
243
#endif
244
   
244
   
245
#ifdef CONFIG_NS16550
245
#ifdef CONFIG_NS16550
246
    kbd_ns16550_init(node);
246
    kbd_ns16550_init(node);
247
#endif
247
#endif
248
}
248
}
249
 
249
 
250
#endif /* CONFIG_SUN_KBD */
250
#endif /* CONFIG_SUN_KBD */
251
 
251
 
252
/** @}
252
/** @}
253
 */
253
 */
254
 
254