source: mainline/uspace/drv/isa/isa.c@ 68414f4a

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

Refactor drivers

  • Rename soft-state structures to have the simplest names
  • Use soft-state structures as a starting point instead of DDF device or function nodes
  • Convert to standard naming scheme
  • Property mode set to 100644
File size: 10.5 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 <ctype.h>
47#include <macros.h>
48#include <malloc.h>
49#include <dirent.h>
50#include <fcntl.h>
51#include <sys/stat.h>
52
53#include <driver.h>
54#include <ops/hw_res.h>
55
56#include <devman.h>
57#include <ipc/devman.h>
58#include <device/hw_res.h>
59
60#define NAME "isa"
61#define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
62
63/** Obtain soft-state pointer from function node pointer */
64#define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
65
66#define ISA_MAX_HW_RES 4
67
68typedef struct isa_fun {
69 function_t *fnode;
70 hw_resource_list_t hw_resources;
71} isa_fun_t;
72
73static hw_resource_list_t *isa_get_fun_resources(function_t *fnode)
74{
75 isa_fun_t *fun = ISA_FUN(fnode);
76 assert(fun != NULL);
77
78 return &fun->hw_resources;
79}
80
81static bool isa_enable_fun_interrupt(function_t *fnode)
82{
83 // TODO
84
85 return false;
86}
87
88static hw_res_ops_t isa_fun_hw_res_ops = {
89 &isa_get_fun_resources,
90 &isa_enable_fun_interrupt
91};
92
93static device_ops_t isa_fun_ops;
94
95static int isa_add_device(device_t *dev);
96
97/** The isa device driver's standard operations */
98static driver_ops_t isa_ops = {
99 .add_device = &isa_add_device
100};
101
102/** The isa device driver structure. */
103static driver_t isa_driver = {
104 .name = NAME,
105 .driver_ops = &isa_ops
106};
107
108static isa_fun_t *isa_fun_create()
109{
110 isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
111 if (fun == NULL)
112 return NULL;
113
114 function_t *fnode = create_function();
115 if (fnode == NULL) {
116 free(fun);
117 return NULL;
118 }
119
120 fun->fnode = fnode;
121 fnode->driver_data = fun;
122 return fun;
123}
124
125static char *fun_conf_read(const char *conf_path)
126{
127 bool suc = false;
128 char *buf = NULL;
129 bool opened = false;
130 int fd;
131 size_t len = 0;
132
133 fd = open(conf_path, O_RDONLY);
134 if (fd < 0) {
135 printf(NAME ": unable to open %s\n", conf_path);
136 goto cleanup;
137 }
138
139 opened = true;
140
141 len = lseek(fd, 0, SEEK_END);
142 lseek(fd, 0, SEEK_SET);
143 if (len == 0) {
144 printf(NAME ": fun_conf_read error: configuration file '%s' "
145 "is empty.\n", conf_path);
146 goto cleanup;
147 }
148
149 buf = malloc(len + 1);
150 if (buf == NULL) {
151 printf(NAME ": fun_conf_read error: memory allocation failed.\n");
152 goto cleanup;
153 }
154
155 if (0 >= read(fd, buf, len)) {
156 printf(NAME ": fun_conf_read error: unable to read file '%s'.\n",
157 conf_path);
158 goto cleanup;
159 }
160
161 buf[len] = 0;
162
163 suc = true;
164
165cleanup:
166 if (!suc && buf != NULL) {
167 free(buf);
168 buf = NULL;
169 }
170
171 if (opened)
172 close(fd);
173
174 return buf;
175}
176
177static char *str_get_line(char *str, char **next)
178{
179 char *line = str;
180
181 if (str == NULL) {
182 *next = NULL;
183 return NULL;
184 }
185
186 while (*str != '\0' && *str != '\n') {
187 str++;
188 }
189
190 if (*str != '\0') {
191 *next = str + 1;
192 } else {
193 *next = NULL;
194 }
195
196 *str = '\0';
197 return line;
198}
199
200static bool line_empty(const char *line)
201{
202 while (line != NULL && *line != 0) {
203 if (!isspace(*line))
204 return false;
205 line++;
206 }
207
208 return true;
209}
210
211static char *get_device_name(char *line)
212{
213 /* Skip leading spaces. */
214 while (*line != '\0' && isspace(*line)) {
215 line++;
216 }
217
218 /* Get the name part of the rest of the line. */
219 strtok(line, ":");
220
221 /* Allocate output buffer. */
222 size_t size = str_size(line) + 1;
223 char *name = malloc(size);
224
225 if (name != NULL) {
226 /* Copy the result to the output buffer. */
227 str_cpy(name, size, line);
228 }
229
230 return name;
231}
232
233static inline char *skip_spaces(char *line)
234{
235 /* Skip leading spaces. */
236 while (*line != '\0' && isspace(*line))
237 line++;
238
239 return line;
240}
241
242static void isa_fun_set_irq(isa_fun_t *fun, int irq)
243{
244 size_t count = fun->hw_resources.count;
245 hw_resource_t *resources = fun->hw_resources.resources;
246
247 if (count < ISA_MAX_HW_RES) {
248 resources[count].type = INTERRUPT;
249 resources[count].res.interrupt.irq = irq;
250
251 fun->hw_resources.count++;
252
253 printf(NAME ": added irq 0x%x to function %s\n", irq,
254 fun->fnode->name);
255 }
256}
257
258static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
259{
260 size_t count = fun->hw_resources.count;
261 hw_resource_t *resources = fun->hw_resources.resources;
262
263 if (count < ISA_MAX_HW_RES) {
264 resources[count].type = IO_RANGE;
265 resources[count].res.io_range.address = addr;
266 resources[count].res.io_range.size = len;
267 resources[count].res.io_range.endianness = LITTLE_ENDIAN;
268
269 fun->hw_resources.count++;
270
271 printf(NAME ": added io range (addr=0x%x, size=0x%x) to "
272 "function %s\n", (unsigned int) addr, (unsigned int) len,
273 fun->fnode->name);
274 }
275}
276
277static void fun_parse_irq(isa_fun_t *fun, char *val)
278{
279 int irq = 0;
280 char *end = NULL;
281
282 val = skip_spaces(val);
283 irq = (int)strtol(val, &end, 0x10);
284
285 if (val != end)
286 isa_fun_set_irq(fun, irq);
287}
288
289static void fun_parse_io_range(isa_fun_t *fun, char *val)
290{
291 size_t addr, len;
292 char *end = NULL;
293
294 val = skip_spaces(val);
295 addr = strtol(val, &end, 0x10);
296
297 if (val == end)
298 return;
299
300 val = skip_spaces(end);
301 len = strtol(val, &end, 0x10);
302
303 if (val == end)
304 return;
305
306 isa_fun_set_io_range(fun, addr, len);
307}
308
309static void get_match_id(char **id, char *val)
310{
311 char *end = val;
312
313 while (!isspace(*end))
314 end++;
315
316 size_t size = end - val + 1;
317 *id = (char *)malloc(size);
318 str_cpy(*id, size, val);
319}
320
321static void fun_parse_match_id(isa_fun_t *fun, char *val)
322{
323 char *id = NULL;
324 int score = 0;
325 char *end = NULL;
326
327 val = skip_spaces(val);
328
329 score = (int)strtol(val, &end, 10);
330 if (val == end) {
331 printf(NAME " : error - could not read match score for "
332 "function %s.\n", fun->fnode->name);
333 return;
334 }
335
336 match_id_t *match_id = create_match_id();
337 if (match_id == NULL) {
338 printf(NAME " : failed to allocate match id for function %s.\n",
339 fun->fnode->name);
340 return;
341 }
342
343 val = skip_spaces(end);
344 get_match_id(&id, val);
345 if (id == NULL) {
346 printf(NAME " : error - could not read match id for "
347 "function %s.\n", fun->fnode->name);
348 delete_match_id(match_id);
349 return;
350 }
351
352 match_id->id = id;
353 match_id->score = score;
354
355 printf(NAME ": adding match id '%s' with score %d to function %s\n", id,
356 score, fun->fnode->name);
357 add_match_id(&fun->fnode->match_ids, match_id);
358}
359
360static bool prop_parse(isa_fun_t *fun, char *line, const char *prop,
361 void (*read_fn)(isa_fun_t *, char *))
362{
363 size_t proplen = str_size(prop);
364
365 if (str_lcmp(line, prop, proplen) == 0) {
366 line += proplen;
367 line = skip_spaces(line);
368 (*read_fn)(fun, line);
369
370 return true;
371 }
372
373 return false;
374}
375
376static void fun_prop_parse(isa_fun_t *fun, char *line)
377{
378 /* Skip leading spaces. */
379 line = skip_spaces(line);
380
381 if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
382 !prop_parse(fun, line, "irq", &fun_parse_irq) &&
383 !prop_parse(fun, line, "match", &fun_parse_match_id))
384 {
385 printf(NAME " error undefined device property at line '%s'\n",
386 line);
387 }
388}
389
390static void fun_hw_res_alloc(isa_fun_t *fun)
391{
392 fun->hw_resources.resources =
393 (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
394}
395
396static char *isa_fun_read_info(char *fun_conf, device_t *dev)
397{
398 char *line;
399 char *fun_name = NULL;
400
401 /* Skip empty lines. */
402 while (true) {
403 line = str_get_line(fun_conf, &fun_conf);
404
405 if (line == NULL) {
406 /* no more lines */
407 return NULL;
408 }
409
410 if (!line_empty(line))
411 break;
412 }
413
414 /* Get device name. */
415 fun_name = get_device_name(line);
416 if (fun_name == NULL)
417 return NULL;
418
419 isa_fun_t *fun = isa_fun_create();
420 if (fun == NULL) {
421 free(fun_name);
422 return NULL;
423 }
424
425 function_t *fnode = fun->fnode;
426 fnode->name = fun_name;
427 fnode->ftype = fun_inner;
428
429 /* Allocate buffer for the list of hardware resources of the device. */
430 fun_hw_res_alloc(fun);
431
432 /* Get properties of the device (match ids, irq and io range). */
433 while (true) {
434 line = str_get_line(fun_conf, &fun_conf);
435
436 if (line_empty(line)) {
437 /* no more device properties */
438 break;
439 }
440
441 /*
442 * Get the device's property from the configuration line
443 * and store it in the device structure.
444 */
445 fun_prop_parse(fun, line);
446 }
447
448 /* Set device operations to the device. */
449 fnode->ops = &isa_fun_ops;
450
451 printf(NAME ": register_function(fun, dev); function is %s.\n",
452 fnode->name);
453 register_function(fnode, dev);
454
455 return fun_conf;
456}
457
458static void fun_conf_parse(char *conf, device_t *dev)
459{
460 while (conf != NULL && *conf != '\0') {
461 conf = isa_fun_read_info(conf, dev);
462 }
463}
464
465static void isa_functions_add(device_t *dev)
466{
467 char *fun_conf;
468
469 fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
470 if (fun_conf != NULL) {
471 fun_conf_parse(fun_conf, dev);
472 free(fun_conf);
473 }
474}
475
476static int isa_add_device(device_t *dev)
477{
478 printf(NAME ": isa_add_device, device handle = %d\n",
479 (int) dev->handle);
480
481 /* Make the bus device more visible. Does not do anything. */
482 printf(NAME ": adding a 'ctl' function\n");
483
484 function_t *ctl = create_function();
485 ctl->ftype = fun_exposed;
486 ctl->name = "ctl";
487 register_function(ctl, dev);
488
489 /* Add functions as specified in the configuration file. */
490 isa_functions_add(dev);
491 printf(NAME ": finished the enumeration of legacy functions\n");
492
493 return EOK;
494}
495
496static void isa_init()
497{
498 isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
499}
500
501int main(int argc, char *argv[])
502{
503 printf(NAME ": HelenOS ISA bus driver\n");
504 isa_init();
505 return driver_main(&isa_driver);
506}
507
508/**
509 * @}
510 */
Note: See TracBrowser for help on using the repository browser.