source: mainline/uspace/drv/isa/isa.c@ 4abc304

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

Split driver.h into ddf/driver.h and ddf/interrupt.h.

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @defgroup isa ISA bus driver.
32 * @brief HelenOS ISA bus driver.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <assert.h>
40#include <stdio.h>
41#include <errno.h>
42#include <bool.h>
43#include <fibril_synch.h>
44#include <stdlib.h>
45#include <str.h>
46#include <str_error.h>
47#include <ctype.h>
48#include <macros.h>
49#include <malloc.h>
50#include <dirent.h>
51#include <fcntl.h>
52#include <sys/stat.h>
53
54#include <ddf/driver.h>
55#include <ops/hw_res.h>
56
57#include <devman.h>
58#include <ipc/devman.h>
59#include <device/hw_res.h>
60
61#define NAME "isa"
62#define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
63
64/** Obtain soft-state pointer from function node pointer */
65#define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
66
67#define ISA_MAX_HW_RES 4
68
69typedef struct isa_fun {
70 ddf_fun_t *fnode;
71 hw_resource_list_t hw_resources;
72} isa_fun_t;
73
74static hw_resource_list_t *isa_get_fun_resources(ddf_fun_t *fnode)
75{
76 isa_fun_t *fun = ISA_FUN(fnode);
77 assert(fun != NULL);
78
79 return &fun->hw_resources;
80}
81
82static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
83{
84 // TODO
85
86 return false;
87}
88
89static hw_res_ops_t isa_fun_hw_res_ops = {
90 &isa_get_fun_resources,
91 &isa_enable_fun_interrupt
92};
93
94static ddf_dev_ops_t isa_fun_ops;
95
96static int isa_add_device(ddf_dev_t *dev);
97
98/** The isa device driver's standard operations */
99static driver_ops_t isa_ops = {
100 .add_device = &isa_add_device
101};
102
103/** The isa device driver structure. */
104static driver_t isa_driver = {
105 .name = NAME,
106 .driver_ops = &isa_ops
107};
108
109static isa_fun_t *isa_fun_create(ddf_dev_t *dev, const char *name)
110{
111 isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
112 if (fun == NULL)
113 return NULL;
114
115 ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
116 if (fnode == NULL) {
117 free(fun);
118 return NULL;
119 }
120
121 fun->fnode = fnode;
122 fnode->driver_data = fun;
123 return fun;
124}
125
126static char *fun_conf_read(const char *conf_path)
127{
128 bool suc = false;
129 char *buf = NULL;
130 bool opened = false;
131 int fd;
132 size_t len = 0;
133
134 fd = open(conf_path, O_RDONLY);
135 if (fd < 0) {
136 printf(NAME ": unable to open %s\n", conf_path);
137 goto cleanup;
138 }
139
140 opened = true;
141
142 len = lseek(fd, 0, SEEK_END);
143 lseek(fd, 0, SEEK_SET);
144 if (len == 0) {
145 printf(NAME ": fun_conf_read error: configuration file '%s' "
146 "is empty.\n", conf_path);
147 goto cleanup;
148 }
149
150 buf = malloc(len + 1);
151 if (buf == NULL) {
152 printf(NAME ": fun_conf_read error: memory allocation failed.\n");
153 goto cleanup;
154 }
155
156 if (0 >= read(fd, buf, len)) {
157 printf(NAME ": fun_conf_read error: unable to read file '%s'.\n",
158 conf_path);
159 goto cleanup;
160 }
161
162 buf[len] = 0;
163
164 suc = true;
165
166cleanup:
167 if (!suc && buf != NULL) {
168 free(buf);
169 buf = NULL;
170 }
171
172 if (opened)
173 close(fd);
174
175 return buf;
176}
177
178static char *str_get_line(char *str, char **next)
179{
180 char *line = str;
181
182 if (str == NULL) {
183 *next = NULL;
184 return NULL;
185 }
186
187 while (*str != '\0' && *str != '\n') {
188 str++;
189 }
190
191 if (*str != '\0') {
192 *next = str + 1;
193 } else {
194 *next = NULL;
195 }
196
197 *str = '\0';
198 return line;
199}
200
201static bool line_empty(const char *line)
202{
203 while (line != NULL && *line != 0) {
204 if (!isspace(*line))
205 return false;
206 line++;
207 }
208
209 return true;
210}
211
212static char *get_device_name(char *line)
213{
214 /* Skip leading spaces. */
215 while (*line != '\0' && isspace(*line)) {
216 line++;
217 }
218
219 /* Get the name part of the rest of the line. */
220 strtok(line, ":");
221
222 /* Allocate output buffer. */
223 size_t size = str_size(line) + 1;
224 char *name = malloc(size);
225
226 if (name != NULL) {
227 /* Copy the result to the output buffer. */
228 str_cpy(name, size, line);
229 }
230
231 return name;
232}
233
234static inline char *skip_spaces(char *line)
235{
236 /* Skip leading spaces. */
237 while (*line != '\0' && isspace(*line))
238 line++;
239
240 return line;
241}
242
243static void isa_fun_set_irq(isa_fun_t *fun, int irq)
244{
245 size_t count = fun->hw_resources.count;
246 hw_resource_t *resources = fun->hw_resources.resources;
247
248 if (count < ISA_MAX_HW_RES) {
249 resources[count].type = INTERRUPT;
250 resources[count].res.interrupt.irq = irq;
251
252 fun->hw_resources.count++;
253
254 printf(NAME ": added irq 0x%x to function %s\n", irq,
255 fun->fnode->name);
256 }
257}
258
259static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
260{
261 size_t count = fun->hw_resources.count;
262 hw_resource_t *resources = fun->hw_resources.resources;
263
264 if (count < ISA_MAX_HW_RES) {
265 resources[count].type = IO_RANGE;
266 resources[count].res.io_range.address = addr;
267 resources[count].res.io_range.size = len;
268 resources[count].res.io_range.endianness = LITTLE_ENDIAN;
269
270 fun->hw_resources.count++;
271
272 printf(NAME ": added io range (addr=0x%x, size=0x%x) to "
273 "function %s\n", (unsigned int) addr, (unsigned int) len,
274 fun->fnode->name);
275 }
276}
277
278static void fun_parse_irq(isa_fun_t *fun, char *val)
279{
280 int irq = 0;
281 char *end = NULL;
282
283 val = skip_spaces(val);
284 irq = (int)strtol(val, &end, 0x10);
285
286 if (val != end)
287 isa_fun_set_irq(fun, irq);
288}
289
290static void fun_parse_io_range(isa_fun_t *fun, char *val)
291{
292 size_t addr, len;
293 char *end = NULL;
294
295 val = skip_spaces(val);
296 addr = strtol(val, &end, 0x10);
297
298 if (val == end)
299 return;
300
301 val = skip_spaces(end);
302 len = strtol(val, &end, 0x10);
303
304 if (val == end)
305 return;
306
307 isa_fun_set_io_range(fun, addr, len);
308}
309
310static void get_match_id(char **id, char *val)
311{
312 char *end = val;
313
314 while (!isspace(*end))
315 end++;
316
317 size_t size = end - val + 1;
318 *id = (char *)malloc(size);
319 str_cpy(*id, size, val);
320}
321
322static void fun_parse_match_id(isa_fun_t *fun, char *val)
323{
324 char *id = NULL;
325 int score = 0;
326 char *end = NULL;
327 int rc;
328
329 val = skip_spaces(val);
330
331 score = (int)strtol(val, &end, 10);
332 if (val == end) {
333 printf(NAME " : error - could not read match score for "
334 "function %s.\n", fun->fnode->name);
335 return;
336 }
337
338 val = skip_spaces(end);
339 get_match_id(&id, val);
340 if (id == NULL) {
341 printf(NAME " : error - could not read match id for "
342 "function %s.\n", fun->fnode->name);
343 return;
344 }
345
346 printf(NAME ": adding match id '%s' with score %d to function %s\n", id,
347 score, fun->fnode->name);
348
349 rc = ddf_fun_add_match_id(fun->fnode, id, score);
350 if (rc != EOK)
351 printf(NAME ": error adding match ID: %s\n", str_error(rc));
352}
353
354static bool prop_parse(isa_fun_t *fun, char *line, const char *prop,
355 void (*read_fn)(isa_fun_t *, char *))
356{
357 size_t proplen = str_size(prop);
358
359 if (str_lcmp(line, prop, proplen) == 0) {
360 line += proplen;
361 line = skip_spaces(line);
362 (*read_fn)(fun, line);
363
364 return true;
365 }
366
367 return false;
368}
369
370static void fun_prop_parse(isa_fun_t *fun, char *line)
371{
372 /* Skip leading spaces. */
373 line = skip_spaces(line);
374
375 if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
376 !prop_parse(fun, line, "irq", &fun_parse_irq) &&
377 !prop_parse(fun, line, "match", &fun_parse_match_id))
378 {
379 printf(NAME " error undefined device property at line '%s'\n",
380 line);
381 }
382}
383
384static void fun_hw_res_alloc(isa_fun_t *fun)
385{
386 fun->hw_resources.resources =
387 (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
388}
389
390static char *isa_fun_read_info(char *fun_conf, ddf_dev_t *dev)
391{
392 char *line;
393 char *fun_name = NULL;
394
395 /* Skip empty lines. */
396 while (true) {
397 line = str_get_line(fun_conf, &fun_conf);
398
399 if (line == NULL) {
400 /* no more lines */
401 return NULL;
402 }
403
404 if (!line_empty(line))
405 break;
406 }
407
408 /* Get device name. */
409 fun_name = get_device_name(line);
410 if (fun_name == NULL)
411 return NULL;
412
413 isa_fun_t *fun = isa_fun_create(dev, fun_name);
414 if (fun == NULL) {
415 free(fun_name);
416 return NULL;
417 }
418
419 /* Allocate buffer for the list of hardware resources of the device. */
420 fun_hw_res_alloc(fun);
421
422 /* Get properties of the device (match ids, irq and io range). */
423 while (true) {
424 line = str_get_line(fun_conf, &fun_conf);
425
426 if (line_empty(line)) {
427 /* no more device properties */
428 break;
429 }
430
431 /*
432 * Get the device's property from the configuration line
433 * and store it in the device structure.
434 */
435 fun_prop_parse(fun, line);
436 }
437
438 /* Set device operations to the device. */
439 fun->fnode->ops = &isa_fun_ops;
440
441 printf(NAME ": Binding function %s.\n", fun->fnode->name);
442
443 /* XXX Handle error */
444 (void) ddf_fun_bind(fun->fnode);
445
446 return fun_conf;
447}
448
449static void fun_conf_parse(char *conf, ddf_dev_t *dev)
450{
451 while (conf != NULL && *conf != '\0') {
452 conf = isa_fun_read_info(conf, dev);
453 }
454}
455
456static void isa_functions_add(ddf_dev_t *dev)
457{
458 char *fun_conf;
459
460 fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
461 if (fun_conf != NULL) {
462 fun_conf_parse(fun_conf, dev);
463 free(fun_conf);
464 }
465}
466
467static int isa_add_device(ddf_dev_t *dev)
468{
469 printf(NAME ": isa_add_device, device handle = %d\n",
470 (int) dev->handle);
471
472 /* Make the bus device more visible. Does not do anything. */
473 printf(NAME ": adding a 'ctl' function\n");
474
475 ddf_fun_t *ctl = ddf_fun_create(dev, fun_exposed, "ctl");
476 if (ctl == NULL) {
477 printf(NAME ": Error creating control function.\n");
478 return EXDEV;
479 }
480
481 if (ddf_fun_bind(ctl) != EOK) {
482 printf(NAME ": Error binding control function.\n");
483 return EXDEV;
484 }
485
486 /* Add functions as specified in the configuration file. */
487 isa_functions_add(dev);
488 printf(NAME ": finished the enumeration of legacy functions\n");
489
490 return EOK;
491}
492
493static void isa_init()
494{
495 isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
496}
497
498int main(int argc, char *argv[])
499{
500 printf(NAME ": HelenOS ISA bus driver\n");
501 isa_init();
502 return ddf_driver_main(&isa_driver);
503}
504
505/**
506 * @}
507 */
Note: See TracBrowser for help on using the repository browser.