00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00039 #include <assert.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <bool.h>
00043 #include <fibril_synch.h>
00044 #include <stdlib.h>
00045 #include <str.h>
00046 #include <str_error.h>
00047 #include <ctype.h>
00048 #include <macros.h>
00049 #include <malloc.h>
00050 #include <dirent.h>
00051 #include <fcntl.h>
00052 #include <sys/stat.h>
00053
00054 #include <ddf/driver.h>
00055 #include <ddf/log.h>
00056 #include <ops/hw_res.h>
00057
00058 #include <devman.h>
00059 #include <ipc/devman.h>
00060 #include <device/hw_res.h>
00061
00062 #define NAME "isa"
00063 #define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
00064
00066 #define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
00067
00068 #define ISA_MAX_HW_RES 4
00069
00070 typedef struct isa_fun {
00071 ddf_fun_t *fnode;
00072 hw_resource_list_t hw_resources;
00073 } isa_fun_t;
00074
00075 static hw_resource_list_t *isa_get_fun_resources(ddf_fun_t *fnode)
00076 {
00077 isa_fun_t *fun = ISA_FUN(fnode);
00078 assert(fun != NULL);
00079
00080 return &fun->hw_resources;
00081 }
00082
00083 static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
00084 {
00085
00086
00087 return false;
00088 }
00089
00090 static hw_res_ops_t isa_fun_hw_res_ops = {
00091 &isa_get_fun_resources,
00092 &isa_enable_fun_interrupt
00093 };
00094
00095 static ddf_dev_ops_t isa_fun_ops;
00096
00097 static int isa_add_device(ddf_dev_t *dev);
00098
00100 static driver_ops_t isa_ops = {
00101 .add_device = &isa_add_device
00102 };
00103
00105 static driver_t isa_driver = {
00106 .name = NAME,
00107 .driver_ops = &isa_ops
00108 };
00109
00110 static isa_fun_t *isa_fun_create(ddf_dev_t *dev, const char *name)
00111 {
00112 isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
00113 if (fun == NULL)
00114 return NULL;
00115
00116 ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
00117 if (fnode == NULL) {
00118 free(fun);
00119 return NULL;
00120 }
00121
00122 fun->fnode = fnode;
00123 fnode->driver_data = fun;
00124 return fun;
00125 }
00126
00127 static char *fun_conf_read(const char *conf_path)
00128 {
00129 bool suc = false;
00130 char *buf = NULL;
00131 bool opened = false;
00132 int fd;
00133 size_t len = 0;
00134
00135 fd = open(conf_path, O_RDONLY);
00136 if (fd < 0) {
00137 ddf_msg(LVL_ERROR, "Unable to open %s", conf_path);
00138 goto cleanup;
00139 }
00140
00141 opened = true;
00142
00143 len = lseek(fd, 0, SEEK_END);
00144 lseek(fd, 0, SEEK_SET);
00145 if (len == 0) {
00146 ddf_msg(LVL_ERROR, "Configuration file '%s' is empty.",
00147 conf_path);
00148 goto cleanup;
00149 }
00150
00151 buf = malloc(len + 1);
00152 if (buf == NULL) {
00153 ddf_msg(LVL_ERROR, "Memory allocation failed.");
00154 goto cleanup;
00155 }
00156
00157 if (0 >= read(fd, buf, len)) {
00158 ddf_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
00159 goto cleanup;
00160 }
00161
00162 buf[len] = 0;
00163
00164 suc = true;
00165
00166 cleanup:
00167 if (!suc && buf != NULL) {
00168 free(buf);
00169 buf = NULL;
00170 }
00171
00172 if (opened)
00173 close(fd);
00174
00175 return buf;
00176 }
00177
00178 static char *str_get_line(char *str, char **next)
00179 {
00180 char *line = str;
00181
00182 if (str == NULL) {
00183 *next = NULL;
00184 return NULL;
00185 }
00186
00187 while (*str != '\0' && *str != '\n') {
00188 str++;
00189 }
00190
00191 if (*str != '\0') {
00192 *next = str + 1;
00193 } else {
00194 *next = NULL;
00195 }
00196
00197 *str = '\0';
00198 return line;
00199 }
00200
00201 static bool line_empty(const char *line)
00202 {
00203 while (line != NULL && *line != 0) {
00204 if (!isspace(*line))
00205 return false;
00206 line++;
00207 }
00208
00209 return true;
00210 }
00211
00212 static char *get_device_name(char *line)
00213 {
00214
00215 while (*line != '\0' && isspace(*line)) {
00216 line++;
00217 }
00218
00219
00220 strtok(line, ":");
00221
00222
00223 size_t size = str_size(line) + 1;
00224 char *name = malloc(size);
00225
00226 if (name != NULL) {
00227
00228 str_cpy(name, size, line);
00229 }
00230
00231 return name;
00232 }
00233
00234 static inline char *skip_spaces(char *line)
00235 {
00236
00237 while (*line != '\0' && isspace(*line))
00238 line++;
00239
00240 return line;
00241 }
00242
00243 static void isa_fun_set_irq(isa_fun_t *fun, int irq)
00244 {
00245 size_t count = fun->hw_resources.count;
00246 hw_resource_t *resources = fun->hw_resources.resources;
00247
00248 if (count < ISA_MAX_HW_RES) {
00249 resources[count].type = INTERRUPT;
00250 resources[count].res.interrupt.irq = irq;
00251
00252 fun->hw_resources.count++;
00253
00254 ddf_msg(LVL_NOTE, "Added irq 0x%x to function %s", irq,
00255 fun->fnode->name);
00256 }
00257 }
00258
00259 static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
00260 {
00261 size_t count = fun->hw_resources.count;
00262 hw_resource_t *resources = fun->hw_resources.resources;
00263
00264 if (count < ISA_MAX_HW_RES) {
00265 resources[count].type = IO_RANGE;
00266 resources[count].res.io_range.address = addr;
00267 resources[count].res.io_range.size = len;
00268 resources[count].res.io_range.endianness = LITTLE_ENDIAN;
00269
00270 fun->hw_resources.count++;
00271
00272 ddf_msg(LVL_NOTE, "Added io range (addr=0x%x, size=0x%x) to "
00273 "function %s", (unsigned int) addr, (unsigned int) len,
00274 fun->fnode->name);
00275 }
00276 }
00277
00278 static void fun_parse_irq(isa_fun_t *fun, char *val)
00279 {
00280 int irq = 0;
00281 char *end = NULL;
00282
00283 val = skip_spaces(val);
00284 irq = (int)strtol(val, &end, 0x10);
00285
00286 if (val != end)
00287 isa_fun_set_irq(fun, irq);
00288 }
00289
00290 static void fun_parse_io_range(isa_fun_t *fun, char *val)
00291 {
00292 size_t addr, len;
00293 char *end = NULL;
00294
00295 val = skip_spaces(val);
00296 addr = strtol(val, &end, 0x10);
00297
00298 if (val == end)
00299 return;
00300
00301 val = skip_spaces(end);
00302 len = strtol(val, &end, 0x10);
00303
00304 if (val == end)
00305 return;
00306
00307 isa_fun_set_io_range(fun, addr, len);
00308 }
00309
00310 static void get_match_id(char **id, char *val)
00311 {
00312 char *end = val;
00313
00314 while (!isspace(*end))
00315 end++;
00316
00317 size_t size = end - val + 1;
00318 *id = (char *)malloc(size);
00319 str_cpy(*id, size, val);
00320 }
00321
00322 static void fun_parse_match_id(isa_fun_t *fun, char *val)
00323 {
00324 char *id = NULL;
00325 int score = 0;
00326 char *end = NULL;
00327 int rc;
00328
00329 val = skip_spaces(val);
00330
00331 score = (int)strtol(val, &end, 10);
00332 if (val == end) {
00333 ddf_msg(LVL_ERROR, "Cannot read match score for function "
00334 "%s.", fun->fnode->name);
00335 return;
00336 }
00337
00338 val = skip_spaces(end);
00339 get_match_id(&id, val);
00340 if (id == NULL) {
00341 ddf_msg(LVL_ERROR, "Cannot read match ID for function %s.",
00342 fun->fnode->name);
00343 return;
00344 }
00345
00346 ddf_msg(LVL_DEBUG, "Adding match id '%s' with score %d to "
00347 "function %s", id, score, fun->fnode->name);
00348
00349 rc = ddf_fun_add_match_id(fun->fnode, id, score);
00350 if (rc != EOK) {
00351 ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
00352 str_error(rc));
00353 }
00354 }
00355
00356 static bool prop_parse(isa_fun_t *fun, char *line, const char *prop,
00357 void (*read_fn)(isa_fun_t *, char *))
00358 {
00359 size_t proplen = str_size(prop);
00360
00361 if (str_lcmp(line, prop, proplen) == 0) {
00362 line += proplen;
00363 line = skip_spaces(line);
00364 (*read_fn)(fun, line);
00365
00366 return true;
00367 }
00368
00369 return false;
00370 }
00371
00372 static void fun_prop_parse(isa_fun_t *fun, char *line)
00373 {
00374
00375 line = skip_spaces(line);
00376
00377 if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
00378 !prop_parse(fun, line, "irq", &fun_parse_irq) &&
00379 !prop_parse(fun, line, "match", &fun_parse_match_id)) {
00380
00381 ddf_msg(LVL_ERROR, "Undefined device property at line '%s'",
00382 line);
00383 }
00384 }
00385
00386 static void fun_hw_res_alloc(isa_fun_t *fun)
00387 {
00388 fun->hw_resources.resources =
00389 (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
00390 }
00391
00392 static char *isa_fun_read_info(char *fun_conf, ddf_dev_t *dev)
00393 {
00394 char *line;
00395 char *fun_name = NULL;
00396
00397
00398 while (true) {
00399 line = str_get_line(fun_conf, &fun_conf);
00400
00401 if (line == NULL) {
00402
00403 return NULL;
00404 }
00405
00406 if (!line_empty(line))
00407 break;
00408 }
00409
00410
00411 fun_name = get_device_name(line);
00412 if (fun_name == NULL)
00413 return NULL;
00414
00415 isa_fun_t *fun = isa_fun_create(dev, fun_name);
00416 if (fun == NULL) {
00417 free(fun_name);
00418 return NULL;
00419 }
00420
00421
00422 fun_hw_res_alloc(fun);
00423
00424
00425 while (true) {
00426 line = str_get_line(fun_conf, &fun_conf);
00427
00428 if (line_empty(line)) {
00429
00430 break;
00431 }
00432
00433
00434
00435
00436
00437 fun_prop_parse(fun, line);
00438 }
00439
00440
00441 fun->fnode->ops = &isa_fun_ops;
00442
00443 ddf_msg(LVL_DEBUG, "Binding function %s.", fun->fnode->name);
00444
00445
00446 (void) ddf_fun_bind(fun->fnode);
00447
00448 return fun_conf;
00449 }
00450
00451 static void fun_conf_parse(char *conf, ddf_dev_t *dev)
00452 {
00453 while (conf != NULL && *conf != '\0') {
00454 conf = isa_fun_read_info(conf, dev);
00455 }
00456 }
00457
00458 static void isa_functions_add(ddf_dev_t *dev)
00459 {
00460 char *fun_conf;
00461
00462 fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
00463 if (fun_conf != NULL) {
00464 fun_conf_parse(fun_conf, dev);
00465 free(fun_conf);
00466 }
00467 }
00468
00469 static int isa_add_device(ddf_dev_t *dev)
00470 {
00471 ddf_msg(LVL_DEBUG, "isa_add_device, device handle = %d",
00472 (int) dev->handle);
00473
00474
00475 ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
00476
00477 ddf_fun_t *ctl = ddf_fun_create(dev, fun_exposed, "ctl");
00478 if (ctl == NULL) {
00479 ddf_msg(LVL_ERROR, "Failed creating control function.");
00480 return EXDEV;
00481 }
00482
00483 if (ddf_fun_bind(ctl) != EOK) {
00484 ddf_msg(LVL_ERROR, "Failed binding control function.");
00485 return EXDEV;
00486 }
00487
00488
00489 isa_functions_add(dev);
00490 ddf_msg(LVL_NOTE, "Finished enumerating legacy functions");
00491
00492 return EOK;
00493 }
00494
00495 static void isa_init()
00496 {
00497 ddf_log_init(NAME, LVL_ERROR);
00498 isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
00499 }
00500
00501 int main(int argc, char *argv[])
00502 {
00503 printf(NAME ": HelenOS ISA bus driver\n");
00504 isa_init();
00505 return ddf_driver_main(&isa_driver);
00506 }
00507