Subversion Repositories HelenOS

Rev

Rev 4347 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4347 Rev 4348
Line 52... Line 52...
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
kbd_type_t kbd_type = KBD_UNKNOWN;
-
 
58
 
-
 
59
#ifdef CONFIG_SUN_KBD
57
#ifdef CONFIG_SUN_KBD
60
 
58
 
61
/** Initialize keyboard.
-
 
62
 *
-
 
63
 * Traverse OpenFirmware device tree in order to find necessary
-
 
64
 * info about the keyboard device.
-
 
65
 *
-
 
66
 * @param node Keyboard device node.
-
 
67
 */
-
 
68
void kbd_init(ofw_tree_node_t *node)
-
 
69
{
-
 
70
    size_t offset;
-
 
71
    uintptr_t aligned_addr;
-
 
72
    ofw_tree_property_t *prop;
-
 
73
    const char *name;
-
 
74
    cir_t cir;
-
 
75
    void *cir_arg;
-
 
76
   
-
 
77
#ifdef CONFIG_NS16550
-
 
78
    ns16550_t *ns16550;
-
 
79
#endif
-
 
80
#ifdef CONFIG_Z8530
59
#ifdef CONFIG_Z8530
81
    z8530_t *z8530;
-
 
82
#endif
-
 
83
   
60
 
84
    name = ofw_tree_node_name(node);
61
static bool kbd_z8530_init(ofw_tree_node_t *node)
85
   
62
{
86
    /*
-
 
87
     * Determine keyboard serial controller type.
63
    const char *name = ofw_tree_node_name(node);
88
     */
-
 
89
    if (strcmp(name, "zs") == 0)
-
 
90
        kbd_type = KBD_Z8530;
-
 
91
    else if (strcmp(name, "su") == 0)
-
 
92
        kbd_type = KBD_NS16550;
-
 
93
   
64
   
94
    if (kbd_type == KBD_UNKNOWN) {
65
    if (str_cmp(name, "zs") != 0)
95
        printf("Unknown keyboard device.\n");
-
 
96
        return;
66
        return false;
97
    }
-
 
98
   
67
   
99
    /*
68
    /*
100
     * Read 'interrupts' property.
69
     * Read 'interrupts' property.
101
     */
70
     */
102
    uint32_t interrupts;
-
 
103
    prop = ofw_tree_getprop(node, "interrupts");
71
    ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
104
    if ((!prop) || (!prop->value))
72
    if ((!prop) || (!prop->value)) {
105
        panic("Cannot find 'interrupt' property.");
73
        printf("z8530: Unable to find interrupts property\n");
-
 
74
        return false;
-
 
75
    }
-
 
76
   
106
    interrupts = *((uint32_t *) prop->value);
77
    uint32_t interrupts = *((uint32_t *) prop->value);
107
   
78
   
108
    /*
79
    /*
109
     * Read 'reg' property.
80
     * Read 'reg' property.
110
     */
81
     */
111
    prop = ofw_tree_getprop(node, "reg");
82
    prop = ofw_tree_getprop(node, "reg");
112
    if ((!prop) || (!prop->value))
83
    if ((!prop) || (!prop->value)) {
113
        panic("Cannot find 'reg' property.");
84
        printf("z8530: Unable to find reg property\n");
-
 
85
        return false;
-
 
86
    }
114
   
87
   
115
    uintptr_t pa;
-
 
116
    size_t size;
88
    size_t size = ((ofw_fhc_reg_t *) prop->value)->size;
117
    inr_t inr;
-
 
118
   
89
   
119
    switch (kbd_type) {
90
    uintptr_t pa;
120
    case KBD_Z8530:
-
 
121
        size = ((ofw_fhc_reg_t *) prop->value)->size;
-
 
122
        if (!ofw_fhc_apply_ranges(node->parent,
91
    if (!ofw_fhc_apply_ranges(node->parent,
123
            ((ofw_fhc_reg_t *) prop->value), &pa)) {
92
        ((ofw_fhc_reg_t *) prop->value), &pa)) {
124
            printf("Failed to determine keyboard address.\n");
93
        printf("z8530: Failed to determine address\n");
125
            return;
94
        return false;
126
        }
95
    }
-
 
96
   
-
 
97
    inr_t inr;
-
 
98
    cir_t cir;
-
 
99
    void *cir_arg;
127
        if (!ofw_fhc_map_interrupt(node->parent,
100
    if (!ofw_fhc_map_interrupt(node->parent,
128
            ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
101
        ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
129
            &cir_arg)) {
102
        &cir_arg)) {
130
            printf("Failed to determine keyboard interrupt.\n");
103
        printf("z8530: Failed to determine interrupt\n");
131
            return;
-
 
132
        }
-
 
133
        break;
-
 
134
       
-
 
135
    case KBD_NS16550:
-
 
136
        size = ((ofw_ebus_reg_t *) prop->value)->size;
-
 
137
        if (!ofw_ebus_apply_ranges(node->parent,
-
 
138
            ((ofw_ebus_reg_t *) prop->value), &pa)) {
-
 
139
            printf("Failed to determine keyboard address.\n");
-
 
140
            return;
104
        return false;
141
        }
-
 
142
        if (!ofw_ebus_map_interrupt(node->parent,
-
 
143
            ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
-
 
144
            &cir_arg)) {
-
 
145
            printf("Failed to determine keyboard interrupt.\n");
-
 
146
            return;
-
 
147
        };
-
 
148
        break;
-
 
149
    default:
-
 
150
        panic("Unexpected keyboard type.");
-
 
151
    }
105
    }
152
   
106
   
153
    /*
107
    /*
154
     * We need to pass aligned address to hw_map().
108
     * We need to pass aligned address to hw_map().
155
     * However, the physical keyboard address can
109
     * However, the physical keyboard address can
156
     * be pretty much unaligned, depending on the
110
     * be pretty much unaligned, depending on the
157
     * underlying controller.
111
     * underlying controller.
158
     */
112
     */
159
    aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
113
    uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
160
    offset = pa - aligned_addr;
114
    size_t offset = pa - aligned_addr;
161
   
115
   
162
    switch (kbd_type) {
-
 
163
#ifdef CONFIG_Z8530
116
    z8530_t *z8530 = (z8530_t *)
164
    case KBD_Z8530:
-
 
165
        z8530 = (z8530_t *) hw_map(aligned_addr, offset + size) +
117
        (hw_map(aligned_addr, offset + size) + offset);
166
            offset;
-
 
167
       
118
   
168
        indev_t *kbrdin_z8530 = z8530_init(z8530, inr, cir, cir_arg);
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();
169
        if (kbrdin_z8530)
122
        if (kbrd_instance) {
170
            kbrd_init(kbrdin_z8530);
123
            indev_t *sink = stdin_wire();
-
 
124
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
-
 
125
            z8530_wire(z8530_instance, kbrd);
-
 
126
        }
-
 
127
    }
171
       
128
   
172
        /*
129
    /*
173
         * This is the necessary evil until the userspace drivers are
130
     * This is the necessary evil until the userspace drivers are
174
         * entirely self-sufficient.
131
     * entirely self-sufficient.
175
         */
132
     */
176
        sysinfo_set_item_val("kbd", NULL, true);
133
    sysinfo_set_item_val("kbd", NULL, true);
177
        sysinfo_set_item_val("kbd.type", NULL, KBD_Z8530);
-
 
178
        sysinfo_set_item_val("kbd.inr", NULL, inr);
134
    sysinfo_set_item_val("kbd.inr", NULL, inr);
179
        sysinfo_set_item_val("kbd.address.kernel", NULL,
135
    sysinfo_set_item_val("kbd.address.kernel", NULL,
180
            (uintptr_t) z8530);
136
        (uintptr_t) z8530);
181
        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);
-
 
139
   
182
        break;
140
    return true;
-
 
141
}
-
 
142
 
183
#endif
143
#endif /* CONFIG_Z8530 */
-
 
144
 
184
#ifdef CONFIG_NS16550
145
#ifdef CONFIG_NS16550
185
    case KBD_NS16550:
-
 
186
        ns16550 = (ns16550_t *) hw_map(aligned_addr, offset + size) +
-
 
187
            offset;
-
 
188
       
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
   
189
        indev_t *kbrdin_ns16550 = ns16550_init(ns16550, inr, cir, cir_arg);
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();
190
        if (kbrdin_ns16550)
208
        if (kbrd_instance) {
191
            kbrd_init(kbrdin_ns16550);
209
            indev_t *sink = stdin_wire();
-
 
210
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
-
 
211
            ns16550_wire(ns16550_instance, kbrd);
-
 
212
        }
-
 
213
    }
192
       
214
   
193
        /*
215
    /*
194
         * This is the necessary evil until the userspace driver is
216
     * This is the necessary evil until the userspace drivers are
195
         * entirely self-sufficient.
217
     * entirely self-sufficient.
196
         */
218
     */
197
        sysinfo_set_item_val("kbd", NULL, true);
219
    sysinfo_set_item_val("kbd", NULL, true);
198
        sysinfo_set_item_val("kbd.type", NULL, KBD_NS16550);
-
 
199
        sysinfo_set_item_val("kbd.inr", NULL, inr);
220
    sysinfo_set_item_val("kbd.inr", NULL, inr);
200
        sysinfo_set_item_val("kbd.address.kernel", NULL,
221
    sysinfo_set_item_val("kbd.address.kernel", NULL,
201
            (uintptr_t) ns16550);
222
        (uintptr_t) ns16550);
202
        sysinfo_set_item_val("kbd.address.physical", NULL, pa);
223
    sysinfo_set_item_val("kbd.address.physical", NULL, pa);
203
        break;
-
 
204
#endif
-
 
205
    default:
-
 
206
        printf("Kernel is not compiled with the necessary keyboard "
224
    sysinfo_set_item_val("kbd.type.ns16550", NULL, true);
207
            "driver this machine requires.\n");
-
 
208
    }
225
   
-
 
226
    return true;
209
}
227
}
210
 
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);
211
#endif
247
#endif
-
 
248
}
-
 
249
 
-
 
250
#endif /* CONFIG_SUN_KBD */
212
 
251
 
213
/** @}
252
/** @}
214
 */
253
 */