source: mainline/uspace/drv/bus/isa/isa.c@ e882e3a

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

Remove include of devman.h where not needed.

  • Property mode set to 100644
File size: 15.4 KB
RevLine 
[892e4e1]1/*
2 * Copyright (c) 2010 Lenka Trochtova
[68414f4a]3 * Copyright (c) 2011 Jiri Svoboda
[d9cf684a]4 * Copyright (c) 2011 Jan Vesely
[892e4e1]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @defgroup isa ISA bus driver.
33 * @brief HelenOS ISA bus driver.
34 * @{
35 */
36
37/** @file
38 */
39
[f278930]40#include <adt/list.h>
[892e4e1]41#include <assert.h>
42#include <stdio.h>
43#include <errno.h>
44#include <bool.h>
45#include <fibril_synch.h>
46#include <stdlib.h>
[c47e1a8]47#include <str.h>
[cd0684d]48#include <str_error.h>
[892e4e1]49#include <ctype.h>
50#include <macros.h>
[c1a8ae52]51#include <malloc.h>
52#include <dirent.h>
53#include <fcntl.h>
[5960b48]54#include <ipc/irc.h>
55#include <ipc/services.h>
56#include <sysinfo.h>
57#include <ns.h>
[c1a8ae52]58#include <sys/stat.h>
[d9cf684a]59#include <ipc/irc.h>
60#include <ipc/services.h>
61#include <sysinfo.h>
62#include <ns.h>
[892e4e1]63
[af6b5157]64#include <ddf/driver.h>
[fc51296]65#include <ddf/log.h>
[41b56084]66#include <ops/hw_res.h>
[5dc9622]67
68#include <device/hw_res.h>
[892e4e1]69
[d9cf684a]70#include "i8237.h"
71
[892e4e1]72#define NAME "isa"
[8b1e15ac]73#define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
[892e4e1]74
[f278930]75/** Obtain soft-state from device node */
76#define ISA_BUS(dev) ((isa_bus_t *) ((dev)->driver_data))
77
78/** Obtain soft-state from function node */
79#define ISA_FUN(fun) ((isa_fun_t *) ((fun)->driver_data))
[68414f4a]80
[d9cf684a]81#define ISA_MAX_HW_RES 5
[5dc9622]82
[f278930]83typedef struct {
84 fibril_mutex_t mutex;
85 ddf_dev_t *dev;
86 ddf_fun_t *fctl;
87 list_t functions;
88} isa_bus_t;
89
[68414f4a]90typedef struct isa_fun {
[f278930]91 fibril_mutex_t mutex;
[83a2f43]92 ddf_fun_t *fnode;
[032e0bb]93 hw_resource_list_t hw_resources;
[f278930]94 link_t bus_link;
[68414f4a]95} isa_fun_t;
[5dc9622]96
[83a2f43]97static hw_resource_list_t *isa_get_fun_resources(ddf_fun_t *fnode)
[5dc9622]98{
[68414f4a]99 isa_fun_t *fun = ISA_FUN(fnode);
100 assert(fun != NULL);
[032e0bb]101
[68414f4a]102 return &fun->hw_resources;
[5dc9622]103}
104
[83a2f43]105static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
[5dc9622]106{
[5960b48]107 /* This is an old ugly way, copied from pci driver */
108 assert(fnode);
109 isa_fun_t *isa_fun = fnode->driver_data;
110
111 sysarg_t apic;
112 sysarg_t i8259;
113
114 async_sess_t *irc_sess = NULL;
115
116 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
117 || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
118 irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
119 SERVICE_IRC, 0, 0);
120 }
121
122 if (!irc_sess)
123 return false;
124
125 assert(isa_fun);
126 const hw_resource_list_t *res = &isa_fun->hw_resources;
127 assert(res);
128 for (size_t i = 0; i < res->count; ++i) {
129 if (res->resources[i].type == INTERRUPT) {
130 const int irq = res->resources[i].res.interrupt.irq;
131
132 async_exch_t *exch = async_exchange_begin(irc_sess);
133 const int rc =
134 async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
135 async_exchange_end(exch);
136
137 if (rc != EOK) {
138 async_hangup(irc_sess);
139 return false;
140 }
141 }
142 }
143
144 async_hangup(irc_sess);
145 return true;
[5dc9622]146}
147
[d9cf684a]148static int isa_dma_channel_fun_setup(ddf_fun_t *fnode,
149 unsigned int channel, uint32_t pa, uint16_t size, uint8_t mode)
150{
151 assert(fnode);
152 isa_fun_t *isa_fun = fnode->driver_data;
153 const hw_resource_list_t *res = &isa_fun->hw_resources;
154 assert(res);
155
156 const unsigned int ch = channel;
157 for (size_t i = 0; i < res->count; ++i) {
158 if (((res->resources[i].type == DMA_CHANNEL_16) &&
159 (res->resources[i].res.dma_channel.dma16 == ch)) ||
160 ((res->resources[i].type == DMA_CHANNEL_8) &&
161 (res->resources[i].res.dma_channel.dma8 == ch))) {
162 return dma_setup_channel(channel, pa, size, mode);
163 }
164 }
165
166 return EINVAL;
[5dc9622]167}
168
[8b1e15ac]169static hw_res_ops_t isa_fun_hw_res_ops = {
[d9cf684a]170 .get_resource_list = isa_get_fun_resources,
171 .enable_interrupt = isa_enable_fun_interrupt,
172 .dma_channel_setup = isa_dma_channel_fun_setup,
[5dc9622]173};
174
[83a2f43]175static ddf_dev_ops_t isa_fun_ops;
[5dc9622]176
[0c0f823b]177static int isa_dev_add(ddf_dev_t *dev);
[f278930]178static int isa_dev_remove(ddf_dev_t *dev);
[5b68e0c]179static int isa_fun_online(ddf_fun_t *fun);
180static int isa_fun_offline(ddf_fun_t *fun);
[892e4e1]181
[032e0bb]182/** The isa device driver's standard operations */
[892e4e1]183static driver_ops_t isa_ops = {
[0c0f823b]184 .dev_add = &isa_dev_add,
[f278930]185 .dev_remove = &isa_dev_remove,
[5b68e0c]186 .fun_online = &isa_fun_online,
187 .fun_offline = &isa_fun_offline
[892e4e1]188};
189
[032e0bb]190/** The isa device driver structure. */
[892e4e1]191static driver_t isa_driver = {
192 .name = NAME,
193 .driver_ops = &isa_ops
194};
195
[f278930]196static isa_fun_t *isa_fun_create(isa_bus_t *isa, const char *name)
[c1a8ae52]197{
[f278930]198 ddf_fun_t *fnode = ddf_fun_create(isa->dev, fun_inner, name);
199 if (fnode == NULL)
[c1a8ae52]200 return NULL;
[032e0bb]201
[f278930]202 isa_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(isa_fun_t));
203 if (fun == NULL)
[c1a8ae52]204 return NULL;
[032e0bb]205
[f278930]206 fibril_mutex_initialize(&fun->mutex);
[68414f4a]207 fun->fnode = fnode;
[8b1e15ac]208 return fun;
[c1a8ae52]209}
210
[68414f4a]211static char *fun_conf_read(const char *conf_path)
[032e0bb]212{
213 bool suc = false;
[c1a8ae52]214 char *buf = NULL;
215 bool opened = false;
[032e0bb]216 int fd;
[c47e1a8]217 size_t len = 0;
[032e0bb]218
[c1a8ae52]219 fd = open(conf_path, O_RDONLY);
220 if (fd < 0) {
[ebcb05a]221 ddf_msg(LVL_ERROR, "Unable to open %s", conf_path);
[c1a8ae52]222 goto cleanup;
[032e0bb]223 }
224
225 opened = true;
226
[c1a8ae52]227 len = lseek(fd, 0, SEEK_END);
[fc51296]228 lseek(fd, 0, SEEK_SET);
[c1a8ae52]229 if (len == 0) {
[ebcb05a]230 ddf_msg(LVL_ERROR, "Configuration file '%s' is empty.",
[fc51296]231 conf_path);
[032e0bb]232 goto cleanup;
[c1a8ae52]233 }
[032e0bb]234
[c1a8ae52]235 buf = malloc(len + 1);
236 if (buf == NULL) {
[ebcb05a]237 ddf_msg(LVL_ERROR, "Memory allocation failed.");
[c1a8ae52]238 goto cleanup;
[032e0bb]239 }
240
[c1a8ae52]241 if (0 >= read(fd, buf, len)) {
[ebcb05a]242 ddf_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
[c1a8ae52]243 goto cleanup;
244 }
[032e0bb]245
[c1a8ae52]246 buf[len] = 0;
[032e0bb]247
[c1a8ae52]248 suc = true;
[032e0bb]249
[c1a8ae52]250cleanup:
[032e0bb]251 if (!suc && buf != NULL) {
252 free(buf);
[c1a8ae52]253 buf = NULL;
254 }
[032e0bb]255
256 if (opened)
257 close(fd);
258
259 return buf;
[c1a8ae52]260}
261
[032e0bb]262static char *str_get_line(char *str, char **next)
263{
[5dc9622]264 char *line = str;
[032e0bb]265
266 if (str == NULL) {
[f928a8a]267 *next = NULL;
268 return NULL;
269 }
[032e0bb]270
271 while (*str != '\0' && *str != '\n') {
[5dc9622]272 str++;
[032e0bb]273 }
274
275 if (*str != '\0') {
[5dc9622]276 *next = str + 1;
277 } else {
278 *next = NULL;
[032e0bb]279 }
280
281 *str = '\0';
[5dc9622]282 return line;
[c1a8ae52]283}
284
285static bool line_empty(const char *line)
286{
[032e0bb]287 while (line != NULL && *line != 0) {
288 if (!isspace(*line))
[c1a8ae52]289 return false;
[032e0bb]290 line++;
291 }
292
293 return true;
[c1a8ae52]294}
295
[032e0bb]296static char *get_device_name(char *line)
297{
298 /* Skip leading spaces. */
299 while (*line != '\0' && isspace(*line)) {
[c1a8ae52]300 line++;
301 }
[032e0bb]302
303 /* Get the name part of the rest of the line. */
304 strtok(line, ":");
305
306 /* Allocate output buffer. */
[5dc9622]307 size_t size = str_size(line) + 1;
308 char *name = malloc(size);
[032e0bb]309
310 if (name != NULL) {
311 /* Copy the result to the output buffer. */
[5dc9622]312 str_cpy(name, size, line);
[c1a8ae52]313 }
314
315 return name;
316}
317
[032e0bb]318static inline char *skip_spaces(char *line)
[c1a8ae52]319{
[032e0bb]320 /* Skip leading spaces. */
321 while (*line != '\0' && isspace(*line))
[c1a8ae52]322 line++;
323
[032e0bb]324 return line;
325}
[c1a8ae52]326
[68414f4a]327static void isa_fun_set_irq(isa_fun_t *fun, int irq)
[c1a8ae52]328{
[68414f4a]329 size_t count = fun->hw_resources.count;
330 hw_resource_t *resources = fun->hw_resources.resources;
[032e0bb]331
[5dc9622]332 if (count < ISA_MAX_HW_RES) {
333 resources[count].type = INTERRUPT;
334 resources[count].res.interrupt.irq = irq;
[032e0bb]335
[68414f4a]336 fun->hw_resources.count++;
[032e0bb]337
[ebcb05a]338 ddf_msg(LVL_NOTE, "Added irq 0x%x to function %s", irq,
[68414f4a]339 fun->fnode->name);
[032e0bb]340 }
[5dc9622]341}
342
[d9cf684a]343static void isa_fun_set_dma(isa_fun_t *fun, int dma)
344{
345 size_t count = fun->hw_resources.count;
346 hw_resource_t *resources = fun->hw_resources.resources;
347
348 if (count < ISA_MAX_HW_RES) {
349 if ((dma > 0) && (dma < 4)) {
350 resources[count].type = DMA_CHANNEL_8;
351 resources[count].res.dma_channel.dma8 = dma;
352
353 fun->hw_resources.count++;
354 ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
355 fun->fnode->name);
356
357 return;
358 }
359
360 if ((dma > 4) && (dma < 8)) {
361 resources[count].type = DMA_CHANNEL_16;
362 resources[count].res.dma_channel.dma16 = dma;
363
364 fun->hw_resources.count++;
365 ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
366 fun->fnode->name);
367
368 return;
369 }
370
371 ddf_msg(LVL_WARN, "Skipped dma 0x%x for function %s", dma,
372 fun->fnode->name);
373 }
374}
375
[68414f4a]376static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
[5dc9622]377{
[68414f4a]378 size_t count = fun->hw_resources.count;
379 hw_resource_t *resources = fun->hw_resources.resources;
[032e0bb]380
[5dc9622]381 if (count < ISA_MAX_HW_RES) {
382 resources[count].type = IO_RANGE;
383 resources[count].res.io_range.address = addr;
384 resources[count].res.io_range.size = len;
[032e0bb]385 resources[count].res.io_range.endianness = LITTLE_ENDIAN;
386
[68414f4a]387 fun->hw_resources.count++;
[032e0bb]388
[fc51296]389 ddf_msg(LVL_NOTE, "Added io range (addr=0x%x, size=0x%x) to "
[ebcb05a]390 "function %s", (unsigned int) addr, (unsigned int) len,
[68414f4a]391 fun->fnode->name);
[032e0bb]392 }
[c1a8ae52]393}
394
[68414f4a]395static void fun_parse_irq(isa_fun_t *fun, char *val)
[c1a8ae52]396{
397 int irq = 0;
398 char *end = NULL;
[032e0bb]399
[8b1e15ac]400 val = skip_spaces(val);
[5cc9eba]401 irq = (int) strtol(val, &end, 10);
[032e0bb]402
403 if (val != end)
[8b1e15ac]404 isa_fun_set_irq(fun, irq);
[c1a8ae52]405}
406
[d9cf684a]407static void fun_parse_dma(isa_fun_t *fun, char *val)
408{
409 unsigned int dma = 0;
410 char *end = NULL;
411
412 val = skip_spaces(val);
413 dma = (unsigned int) strtol(val, &end, 10);
414
415 if (val != end)
416 isa_fun_set_dma(fun, dma);
417}
418
[68414f4a]419static void fun_parse_io_range(isa_fun_t *fun, char *val)
[c1a8ae52]420{
[5dc9622]421 size_t addr, len;
422 char *end = NULL;
[032e0bb]423
[8b1e15ac]424 val = skip_spaces(val);
[5dc9622]425 addr = strtol(val, &end, 0x10);
[032e0bb]426
427 if (val == end)
[5dc9622]428 return;
[032e0bb]429
[8b1e15ac]430 val = skip_spaces(end);
[5dc9622]431 len = strtol(val, &end, 0x10);
[032e0bb]432
433 if (val == end)
[5dc9622]434 return;
[032e0bb]435
[8b1e15ac]436 isa_fun_set_io_range(fun, addr, len);
[c1a8ae52]437}
438
[5dc9622]439static void get_match_id(char **id, char *val)
[c1a8ae52]440{
[5dc9622]441 char *end = val;
[032e0bb]442
443 while (!isspace(*end))
[5dc9622]444 end++;
[032e0bb]445
[f928a8a]446 size_t size = end - val + 1;
[5dc9622]447 *id = (char *)malloc(size);
[032e0bb]448 str_cpy(*id, size, val);
[5dc9622]449}
450
[68414f4a]451static void fun_parse_match_id(isa_fun_t *fun, char *val)
[032e0bb]452{
[5dc9622]453 char *id = NULL;
454 int score = 0;
455 char *end = NULL;
[cd0684d]456 int rc;
[032e0bb]457
[68414f4a]458 val = skip_spaces(val);
[032e0bb]459
[5fe1c32]460 score = (int)strtol(val, &end, 10);
[5dc9622]461 if (val == end) {
[fc51296]462 ddf_msg(LVL_ERROR, "Cannot read match score for function "
[ebcb05a]463 "%s.", fun->fnode->name);
[5dc9622]464 return;
465 }
[032e0bb]466
[bab6388]467 val = skip_spaces(end);
[5dc9622]468 get_match_id(&id, val);
[032e0bb]469 if (id == NULL) {
[ebcb05a]470 ddf_msg(LVL_ERROR, "Cannot read match ID for function %s.",
[fc51296]471 fun->fnode->name);
[5dc9622]472 return;
473 }
[032e0bb]474
[fc51296]475 ddf_msg(LVL_DEBUG, "Adding match id '%s' with score %d to "
[ebcb05a]476 "function %s", id, score, fun->fnode->name);
[cd0684d]477
478 rc = ddf_fun_add_match_id(fun->fnode, id, score);
[fc51296]479 if (rc != EOK) {
[ebcb05a]480 ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
[fc51296]481 str_error(rc));
482 }
[ef9460b]483
484 free(id);
[c1a8ae52]485}
486
[68414f4a]487static bool prop_parse(isa_fun_t *fun, char *line, const char *prop,
488 void (*read_fn)(isa_fun_t *, char *))
[5fe1c32]489{
490 size_t proplen = str_size(prop);
[032e0bb]491
492 if (str_lcmp(line, prop, proplen) == 0) {
[5fe1c32]493 line += proplen;
494 line = skip_spaces(line);
[8b1e15ac]495 (*read_fn)(fun, line);
[032e0bb]496
[5fe1c32]497 return true;
498 }
[032e0bb]499
500 return false;
[5fe1c32]501}
502
[68414f4a]503static void fun_prop_parse(isa_fun_t *fun, char *line)
[c1a8ae52]504{
[032e0bb]505 /* Skip leading spaces. */
[c1a8ae52]506 line = skip_spaces(line);
[032e0bb]507
[68414f4a]508 if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
509 !prop_parse(fun, line, "irq", &fun_parse_irq) &&
[d9cf684a]510 !prop_parse(fun, line, "dma", &fun_parse_dma) &&
[fc51296]511 !prop_parse(fun, line, "match", &fun_parse_match_id)) {
512
[ebcb05a]513 ddf_msg(LVL_ERROR, "Undefined device property at line '%s'",
[fc51296]514 line);
[032e0bb]515 }
[c1a8ae52]516}
517
[68414f4a]518static void fun_hw_res_alloc(isa_fun_t *fun)
[5dc9622]519{
[818fffe]520 fun->hw_resources.resources =
[d9cf684a]521 (hw_resource_t *) malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
[5dc9622]522}
523
[f278930]524static void fun_hw_res_free(isa_fun_t *fun)
525{
526 free(fun->hw_resources.resources);
527 fun->hw_resources.resources = NULL;
528}
529
530static char *isa_fun_read_info(char *fun_conf, isa_bus_t *isa)
[c1a8ae52]531{
532 char *line;
[8b1e15ac]533 char *fun_name = NULL;
[032e0bb]534
535 /* Skip empty lines. */
536 while (true) {
[8b1e15ac]537 line = str_get_line(fun_conf, &fun_conf);
[032e0bb]538
539 if (line == NULL) {
540 /* no more lines */
[c1a8ae52]541 return NULL;
542 }
[032e0bb]543
544 if (!line_empty(line))
[c1a8ae52]545 break;
546 }
[032e0bb]547
548 /* Get device name. */
[8b1e15ac]549 fun_name = get_device_name(line);
550 if (fun_name == NULL)
[c1a8ae52]551 return NULL;
[032e0bb]552
[f278930]553 isa_fun_t *fun = isa_fun_create(isa, fun_name);
[8b1e15ac]554 if (fun == NULL) {
555 free(fun_name);
[c1a8ae52]556 return NULL;
557 }
[032e0bb]558
559 /* Allocate buffer for the list of hardware resources of the device. */
[68414f4a]560 fun_hw_res_alloc(fun);
[032e0bb]561
562 /* Get properties of the device (match ids, irq and io range). */
563 while (true) {
[8b1e15ac]564 line = str_get_line(fun_conf, &fun_conf);
[032e0bb]565
[5dc9622]566 if (line_empty(line)) {
[032e0bb]567 /* no more device properties */
[5dc9622]568 break;
569 }
[032e0bb]570
571 /*
572 * Get the device's property from the configuration line
573 * and store it in the device structure.
574 */
[68414f4a]575 fun_prop_parse(fun, line);
[c1a8ae52]576 }
[032e0bb]577
578 /* Set device operations to the device. */
[97a62fe]579 fun->fnode->ops = &isa_fun_ops;
580
[ebcb05a]581 ddf_msg(LVL_DEBUG, "Binding function %s.", fun->fnode->name);
[032e0bb]582
[97a62fe]583 /* XXX Handle error */
584 (void) ddf_fun_bind(fun->fnode);
[032e0bb]585
[f278930]586 list_append(&fun->bus_link, &isa->functions);
587
[8b1e15ac]588 return fun_conf;
[c1a8ae52]589}
590
[f278930]591static void fun_conf_parse(char *conf, isa_bus_t *isa)
[c1a8ae52]592{
[032e0bb]593 while (conf != NULL && *conf != '\0') {
[f278930]594 conf = isa_fun_read_info(conf, isa);
[032e0bb]595 }
[c1a8ae52]596}
597
[f278930]598static void isa_functions_add(isa_bus_t *isa)
[c1a8ae52]599{
[8b1e15ac]600 char *fun_conf;
[032e0bb]601
[68414f4a]602 fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
[8b1e15ac]603 if (fun_conf != NULL) {
[f278930]604 fun_conf_parse(fun_conf, isa);
[8b1e15ac]605 free(fun_conf);
[c1a8ae52]606 }
607}
[892e4e1]608
[0c0f823b]609static int isa_dev_add(ddf_dev_t *dev)
[892e4e1]610{
[f278930]611 isa_bus_t *isa;
612
[0c0f823b]613 ddf_msg(LVL_DEBUG, "isa_dev_add, device handle = %d",
[ab3a851]614 (int) dev->handle);
[032e0bb]615
[f278930]616 isa = ddf_dev_data_alloc(dev, sizeof(isa_bus_t));
617 if (isa == NULL)
618 return ENOMEM;
619
620 fibril_mutex_initialize(&isa->mutex);
621 isa->dev = dev;
622 list_initialize(&isa->functions);
623
[8b1e15ac]624 /* Make the bus device more visible. Does not do anything. */
[ebcb05a]625 ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
[8b1e15ac]626
[f278930]627 fibril_mutex_lock(&isa->mutex);
628
629 isa->fctl = ddf_fun_create(dev, fun_exposed, "ctl");
630 if (isa->fctl == NULL) {
[ebcb05a]631 ddf_msg(LVL_ERROR, "Failed creating control function.");
[97a62fe]632 return EXDEV;
633 }
634
[f278930]635 if (ddf_fun_bind(isa->fctl) != EOK) {
636 ddf_fun_destroy(isa->fctl);
[ebcb05a]637 ddf_msg(LVL_ERROR, "Failed binding control function.");
[97a62fe]638 return EXDEV;
639 }
[8b1e15ac]640
[68414f4a]641 /* Add functions as specified in the configuration file. */
[f278930]642 isa_functions_add(isa);
[ebcb05a]643 ddf_msg(LVL_NOTE, "Finished enumerating legacy functions");
[032e0bb]644
[f278930]645 fibril_mutex_unlock(&isa->mutex);
646
647 return EOK;
648}
649
650static int isa_dev_remove(ddf_dev_t *dev)
651{
652 isa_bus_t *isa = ISA_BUS(dev);
653 int rc;
654
655 fibril_mutex_lock(&isa->mutex);
656
657 while (!list_empty(&isa->functions)) {
658 isa_fun_t *fun = list_get_instance(list_first(&isa->functions),
659 isa_fun_t, bus_link);
660
661 rc = ddf_fun_offline(fun->fnode);
662 if (rc != EOK) {
663 fibril_mutex_unlock(&isa->mutex);
664 ddf_msg(LVL_ERROR, "Failed offlining %s", fun->fnode->name);
665 return rc;
666 }
667
668 rc = ddf_fun_unbind(fun->fnode);
669 if (rc != EOK) {
670 fibril_mutex_unlock(&isa->mutex);
671 ddf_msg(LVL_ERROR, "Failed unbinding %s", fun->fnode->name);
672 return rc;
673 }
674
675 list_remove(&fun->bus_link);
676
677 fun_hw_res_free(fun);
678 ddf_fun_destroy(fun->fnode);
679 }
680
681 if (ddf_fun_unbind(isa->fctl) != EOK) {
682 fibril_mutex_unlock(&isa->mutex);
683 ddf_msg(LVL_ERROR, "Failed unbinding control function.");
684 return EXDEV;
685 }
686
687 fibril_mutex_unlock(&isa->mutex);
688
[df747b9c]689 return EOK;
[892e4e1]690}
691
[5b68e0c]692static int isa_fun_online(ddf_fun_t *fun)
693{
694 ddf_msg(LVL_DEBUG, "isa_fun_online()");
695 return ddf_fun_online(fun);
696}
697
698static int isa_fun_offline(ddf_fun_t *fun)
699{
700 ddf_msg(LVL_DEBUG, "isa_fun_offline()");
701 return ddf_fun_offline(fun);
702}
703
704
[d9cf684a]705static void isa_init()
[5dc9622]706{
[fc51296]707 ddf_log_init(NAME, LVL_ERROR);
[68414f4a]708 isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
[5dc9622]709}
710
[892e4e1]711int main(int argc, char *argv[])
712{
[032e0bb]713 printf(NAME ": HelenOS ISA bus driver\n");
[5dc9622]714 isa_init();
[83a2f43]715 return ddf_driver_main(&isa_driver);
[892e4e1]716}
717
718/**
719 * @}
720 */
Note: See TracBrowser for help on using the repository browser.