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