source: mainline/uspace/drv/platform/icp/icp.c@ 36f0738

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36f0738 was b446b02, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Enumerate APIC and i8259 via DDF.

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
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/**
30 * @defgroup icp IntegratorCP platform driver.
31 * @brief HelenOS IntegratorCP platform driver.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <stdio.h>
40#include <errno.h>
41#include <irc.h>
42#include <stdbool.h>
43#include <stdlib.h>
44
45#include <ddf/driver.h>
46#include <ddf/log.h>
47#include <ops/hw_res.h>
48#include <ops/pio_window.h>
49
50#define NAME "icp"
51
52enum {
53 icp_kbd_base = 0x18000000,
54 icp_kbd_irq = 3,
55 icp_mouse_base = 0x19000000,
56 icp_mouse_irq = 4,
57 icp_ic_base = 0x14000000
58};
59
60typedef struct icp_fun {
61 hw_resource_list_t hw_resources;
62} icp_fun_t;
63
64static int icp_dev_add(ddf_dev_t *dev);
65
66static driver_ops_t icp_ops = {
67 .dev_add = &icp_dev_add
68};
69
70static driver_t icp_driver = {
71 .name = NAME,
72 .driver_ops = &icp_ops
73};
74
75static hw_resource_t icp_kbd_res[] = {
76 {
77 .type = MEM_RANGE,
78 .res.mem_range = {
79 .address = icp_kbd_base,
80 .size = 9,
81 .relative = false,
82 .endianness = LITTLE_ENDIAN
83 }
84 },
85 {
86 .type = INTERRUPT,
87 .res.interrupt = {
88 .irq = icp_kbd_irq
89 }
90 }
91};
92
93static hw_resource_t icp_mouse_res[] = {
94 {
95 .type = MEM_RANGE,
96 .res.mem_range = {
97 .address = icp_mouse_base,
98 .size = 9,
99 .relative = false,
100 .endianness = LITTLE_ENDIAN
101 }
102 },
103 {
104 .type = INTERRUPT,
105 .res.interrupt = {
106 .irq = icp_mouse_irq
107 }
108 }
109};
110
111static hw_resource_t icp_ic_res[] = {
112 {
113 .type = MEM_RANGE,
114 .res.mem_range = {
115 .address = icp_ic_base,
116 .size = 40,
117 .relative = false,
118 .endianness = LITTLE_ENDIAN
119 }
120 }
121};
122
123static pio_window_t icp_pio_window = {
124 .mem = {
125 .base = 0,
126 .size = -1
127 }
128};
129
130static icp_fun_t icp_kbd_fun_proto = {
131 .hw_resources = {
132 sizeof(icp_kbd_res) / sizeof(icp_kbd_res[0]),
133 icp_kbd_res
134 },
135};
136
137static icp_fun_t icp_mouse_fun_proto = {
138 .hw_resources = {
139 sizeof(icp_mouse_res) / sizeof(icp_mouse_res[0]),
140 icp_mouse_res
141 },
142};
143
144static icp_fun_t icp_ic_fun_proto = {
145 .hw_resources = {
146 sizeof(icp_ic_res) / sizeof(icp_ic_res[0]),
147 icp_ic_res
148 },
149};
150
151/** Obtain function soft-state from DDF function node */
152static icp_fun_t *icp_fun(ddf_fun_t *fnode)
153{
154 return ddf_fun_data_get(fnode);
155}
156
157static hw_resource_list_t *icp_get_resources(ddf_fun_t *fnode)
158{
159 icp_fun_t *fun = icp_fun(fnode);
160
161 assert(fun != NULL);
162 return &fun->hw_resources;
163}
164
165static bool icp_fun_owns_interrupt(icp_fun_t *fun, int irq)
166{
167 const hw_resource_list_t *res = &fun->hw_resources;
168
169 /* Check that specified irq really belongs to the function */
170 for (size_t i = 0; i < res->count; ++i) {
171 if (res->resources[i].type == INTERRUPT &&
172 res->resources[i].res.interrupt.irq == irq) {
173 return true;
174 }
175 }
176
177 return false;
178}
179
180static int icp_fun_enable_interrupt(ddf_fun_t *fnode, int irq)
181{
182 icp_fun_t *fun = icp_fun(fnode);
183
184 if (!icp_fun_owns_interrupt(fun, irq))
185 return EINVAL;
186
187 return irc_enable_interrupt(irq);
188}
189
190static int icp_fun_disable_interrupt(ddf_fun_t *fnode, int irq)
191{
192 icp_fun_t *fun = icp_fun(fnode);
193
194 if (!icp_fun_owns_interrupt(fun, irq))
195 return EINVAL;
196
197 return irc_disable_interrupt(irq);
198}
199
200static int icp_fun_clear_interrupt(ddf_fun_t *fnode, int irq)
201{
202 icp_fun_t *fun = icp_fun(fnode);
203
204 if (!icp_fun_owns_interrupt(fun, irq))
205 return EINVAL;
206
207 return irc_clear_interrupt(irq);
208}
209
210static pio_window_t *icp_get_pio_window(ddf_fun_t *fnode)
211{
212 return &icp_pio_window;
213}
214
215static hw_res_ops_t icp_hw_res_ops = {
216 .get_resource_list = &icp_get_resources,
217 .enable_interrupt = &icp_fun_enable_interrupt,
218 .disable_interrupt = &icp_fun_disable_interrupt,
219 .clear_interrupt = &icp_fun_clear_interrupt
220};
221
222static pio_window_ops_t icp_pio_window_ops = {
223 .get_pio_window = &icp_get_pio_window
224};
225
226static ddf_dev_ops_t icp_fun_ops = {
227 .interfaces = {
228 [HW_RES_DEV_IFACE] = &icp_hw_res_ops,
229 [PIO_WINDOW_DEV_IFACE] = &icp_pio_window_ops
230 }
231};
232
233static int icp_add_fun(ddf_dev_t *dev, const char *name, const char *str_match_id,
234 icp_fun_t *fun_proto)
235{
236 ddf_msg(LVL_NOTE, "Adding function '%s'.", name);
237
238 ddf_fun_t *fnode = NULL;
239 int rc;
240
241 /* Create new device. */
242 fnode = ddf_fun_create(dev, fun_inner, name);
243 if (fnode == NULL) {
244 ddf_msg(LVL_ERROR, "Error creating function '%s'", name);
245 rc = ENOMEM;
246 goto error;
247 }
248
249 icp_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(icp_fun_t));
250 *fun = *fun_proto;
251
252 /* Add match ID */
253 rc = ddf_fun_add_match_id(fnode, str_match_id, 100);
254 if (rc != EOK) {
255 ddf_msg(LVL_ERROR, "Error adding match ID");
256 goto error;
257 }
258
259 /* Set provided operations to the device. */
260 ddf_fun_set_ops(fnode, &icp_fun_ops);
261
262 /* Register function. */
263 if (ddf_fun_bind(fnode) != EOK) {
264 ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
265 goto error;
266 }
267
268 return EOK;
269
270error:
271 if (fnode != NULL)
272 ddf_fun_destroy(fnode);
273
274 return rc;
275}
276
277static int icp_add_functions(ddf_dev_t *dev)
278{
279 int rc;
280
281 rc = icp_add_fun(dev, "intctl", "integratorcp/intctl",
282 &icp_ic_fun_proto);
283 if (rc != EOK)
284 return rc;
285
286 rc = icp_add_fun(dev, "kbd", "arm/pl050", &icp_kbd_fun_proto);
287 if (rc != EOK)
288 return rc;
289
290 rc = icp_add_fun(dev, "mouse", "arm/pl050", &icp_mouse_fun_proto);
291 if (rc != EOK)
292 return rc;
293
294 return EOK;
295}
296
297/** Add device. */
298static int icp_dev_add(ddf_dev_t *dev)
299{
300 ddf_msg(LVL_NOTE, "icp_dev_add, device handle = %d",
301 (int)ddf_dev_get_handle(dev));
302
303 /* Register functions. */
304 if (icp_add_functions(dev)) {
305 ddf_msg(LVL_ERROR, "Failed to add functions for ICP platform.");
306 }
307
308 return EOK;
309}
310
311int main(int argc, char *argv[])
312{
313 int rc;
314
315 printf(NAME ": HelenOS IntegratorCP platform driver\n");
316
317 rc = ddf_log_init(NAME);
318 if (rc != EOK) {
319 printf(NAME ": Failed initializing logging service");
320 return 1;
321 }
322
323 return ddf_driver_main(&icp_driver);
324}
325
326/**
327 * @}
328 */
Note: See TracBrowser for help on using the repository browser.