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 <ipc/services.h>
00041 #include <ipc/ns.h>
00042 #include <async.h>
00043 #include <stdio.h>
00044 #include <errno.h>
00045 #include <bool.h>
00046 #include <fibril_synch.h>
00047 #include <stdlib.h>
00048 #include <str.h>
00049 #include <str_error.h>
00050 #include <ctype.h>
00051 #include <errno.h>
00052 #include <inttypes.h>
00053 #include <devman.h>
00054
00055 #include <ipc/driver.h>
00056
00057 #include "dev_iface.h"
00058 #include "ddf/driver.h"
00059 #include "ddf/interrupt.h"
00060
00062 static driver_t *driver;
00063
00065 LIST_INITIALIZE(functions);
00066 FIBRIL_MUTEX_INITIALIZE(functions_mutex);
00067
00069 static interrupt_context_list_t interrupt_contexts;
00070
00071 static irq_cmd_t default_cmds[] = {
00072 {
00073 .cmd = CMD_ACCEPT
00074 }
00075 };
00076
00077 static irq_code_t default_pseudocode = {
00078 sizeof(default_cmds) / sizeof(irq_cmd_t),
00079 default_cmds
00080 };
00081
00082 static ddf_dev_t *create_device(void);
00083 static void delete_device(ddf_dev_t *);
00084 static remote_handler_t *function_get_default_handler(ddf_fun_t *);
00085 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
00086
00087 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
00088 {
00089 int id = (int)IPC_GET_IMETHOD(*icall);
00090 interrupt_context_t *ctx;
00091
00092 ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
00093 if (ctx != NULL && ctx->handler != NULL)
00094 (*ctx->handler)(ctx->dev, iid, icall);
00095 }
00096
00097 interrupt_context_t *create_interrupt_context(void)
00098 {
00099 interrupt_context_t *ctx;
00100
00101 ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
00102 if (ctx != NULL)
00103 memset(ctx, 0, sizeof(interrupt_context_t));
00104
00105 return ctx;
00106 }
00107
00108 void delete_interrupt_context(interrupt_context_t *ctx)
00109 {
00110 if (ctx != NULL)
00111 free(ctx);
00112 }
00113
00114 void init_interrupt_context_list(interrupt_context_list_t *list)
00115 {
00116 memset(list, 0, sizeof(interrupt_context_list_t));
00117 fibril_mutex_initialize(&list->mutex);
00118 list_initialize(&list->contexts);
00119 }
00120
00121 void
00122 add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
00123 {
00124 fibril_mutex_lock(&list->mutex);
00125 ctx->id = list->curr_id++;
00126 list_append(&ctx->link, &list->contexts);
00127 fibril_mutex_unlock(&list->mutex);
00128 }
00129
00130 void remove_interrupt_context(interrupt_context_list_t *list,
00131 interrupt_context_t *ctx)
00132 {
00133 fibril_mutex_lock(&list->mutex);
00134 list_remove(&ctx->link);
00135 fibril_mutex_unlock(&list->mutex);
00136 }
00137
00138 interrupt_context_t *
00139 find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
00140 {
00141 fibril_mutex_lock(&list->mutex);
00142
00143 link_t *link = list->contexts.next;
00144 interrupt_context_t *ctx;
00145
00146 while (link != &list->contexts) {
00147 ctx = list_get_instance(link, interrupt_context_t, link);
00148 if (ctx->id == id) {
00149 fibril_mutex_unlock(&list->mutex);
00150 return ctx;
00151 }
00152 link = link->next;
00153 }
00154
00155 fibril_mutex_unlock(&list->mutex);
00156 return NULL;
00157 }
00158
00159 interrupt_context_t *
00160 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
00161 {
00162 fibril_mutex_lock(&list->mutex);
00163
00164 link_t *link = list->contexts.next;
00165 interrupt_context_t *ctx;
00166
00167 while (link != &list->contexts) {
00168 ctx = list_get_instance(link, interrupt_context_t, link);
00169 if (ctx->irq == irq && ctx->dev == dev) {
00170 fibril_mutex_unlock(&list->mutex);
00171 return ctx;
00172 }
00173 link = link->next;
00174 }
00175
00176 fibril_mutex_unlock(&list->mutex);
00177 return NULL;
00178 }
00179
00180
00181 int
00182 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
00183 irq_code_t *pseudocode)
00184 {
00185 interrupt_context_t *ctx = create_interrupt_context();
00186
00187 ctx->dev = dev;
00188 ctx->irq = irq;
00189 ctx->handler = handler;
00190
00191 add_interrupt_context(&interrupt_contexts, ctx);
00192
00193 if (pseudocode == NULL)
00194 pseudocode = &default_pseudocode;
00195
00196 int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
00197 if (res != EOK) {
00198 remove_interrupt_context(&interrupt_contexts, ctx);
00199 delete_interrupt_context(ctx);
00200 }
00201
00202 return res;
00203 }
00204
00205 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
00206 {
00207 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
00208 dev, irq);
00209 int res = unregister_irq(irq, dev->handle);
00210
00211 if (ctx != NULL) {
00212 remove_interrupt_context(&interrupt_contexts, ctx);
00213 delete_interrupt_context(ctx);
00214 }
00215
00216 return res;
00217 }
00218
00219 static void add_to_functions_list(ddf_fun_t *fun)
00220 {
00221 fibril_mutex_lock(&functions_mutex);
00222 list_append(&fun->link, &functions);
00223 fibril_mutex_unlock(&functions_mutex);
00224 }
00225
00226 static void remove_from_functions_list(ddf_fun_t *fun)
00227 {
00228 fibril_mutex_lock(&functions_mutex);
00229 list_remove(&fun->link);
00230 fibril_mutex_unlock(&functions_mutex);
00231 }
00232
00233 static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle)
00234 {
00235 ddf_fun_t *fun = NULL;
00236
00237 fibril_mutex_lock(&functions_mutex);
00238 link_t *link = functions->next;
00239
00240 while (link != functions) {
00241 fun = list_get_instance(link, ddf_fun_t, link);
00242 if (fun->handle == handle) {
00243 fibril_mutex_unlock(&functions_mutex);
00244 return fun;
00245 }
00246
00247 link = link->next;
00248 }
00249
00250 fibril_mutex_unlock(&functions_mutex);
00251
00252 return NULL;
00253 }
00254
00255 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
00256 {
00257 char *dev_name = NULL;
00258 int res;
00259
00260 devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
00261 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
00262
00263 ddf_dev_t *dev = create_device();
00264 dev->handle = dev_handle;
00265
00266 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
00267 dev->name = dev_name;
00268
00269
00270
00271
00272
00273 (void) parent_fun_handle;
00274
00275 res = driver->driver_ops->add_device(dev);
00276 if (res != EOK)
00277 delete_device(dev);
00278
00279 async_answer_0(iid, res);
00280 }
00281
00282 static void driver_connection_devman(ipc_callid_t iid, ipc_call_t *icall)
00283 {
00284
00285 async_answer_0(iid, EOK);
00286
00287 bool cont = true;
00288 while (cont) {
00289 ipc_call_t call;
00290 ipc_callid_t callid = async_get_call(&call);
00291
00292 switch (IPC_GET_IMETHOD(call)) {
00293 case IPC_M_PHONE_HUNGUP:
00294 cont = false;
00295 continue;
00296 case DRIVER_ADD_DEVICE:
00297 driver_add_device(callid, &call);
00298 break;
00299 default:
00300 async_answer_0(callid, ENOENT);
00301 }
00302 }
00303 }
00304
00311 static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv)
00312 {
00313
00314
00315
00316
00317 devman_handle_t handle = IPC_GET_ARG2(*icall);
00318 ddf_fun_t *fun = driver_get_function(&functions, handle);
00319
00320 if (fun == NULL) {
00321 printf("%s: driver_connection_gen error - no function with handle"
00322 " %" PRIun " was found.\n", driver->name, handle);
00323 async_answer_0(iid, ENOENT);
00324 return;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333 int ret = EOK;
00334
00335 if (fun->ops != NULL && fun->ops->open != NULL)
00336 ret = (*fun->ops->open)(fun);
00337
00338 async_answer_0(iid, ret);
00339 if (ret != EOK)
00340 return;
00341
00342 while (1) {
00343 ipc_callid_t callid;
00344 ipc_call_t call;
00345 callid = async_get_call(&call);
00346 sysarg_t method = IPC_GET_IMETHOD(call);
00347 int iface_idx;
00348
00349 switch (method) {
00350 case IPC_M_PHONE_HUNGUP:
00351
00352 if (fun->ops != NULL && fun->ops->close != NULL)
00353 (*fun->ops->close)(fun);
00354 async_answer_0(callid, EOK);
00355 return;
00356 default:
00357
00358
00359 iface_idx = DEV_IFACE_IDX(method);
00360
00361 if (!is_valid_iface_idx(iface_idx)) {
00362 remote_handler_t *default_handler =
00363 function_get_default_handler(fun);
00364 if (default_handler != NULL) {
00365 (*default_handler)(fun, callid, &call);
00366 break;
00367 }
00368
00369
00370
00371
00372
00373 printf("%s: driver_connection_gen error - "
00374 "invalid interface id %d.",
00375 driver->name, iface_idx);
00376 async_answer_0(callid, ENOTSUP);
00377 break;
00378 }
00379
00380
00381
00382
00383 void *ops = function_get_ops(fun, iface_idx);
00384 if (ops == NULL) {
00385 printf("%s: driver_connection_gen error - ",
00386 driver->name);
00387 printf("Function with handle %" PRIun " has no interface "
00388 "with id %d.\n", handle, iface_idx);
00389 async_answer_0(callid, ENOTSUP);
00390 break;
00391 }
00392
00393
00394
00395
00396
00397 remote_iface_t *rem_iface = get_remote_iface(iface_idx);
00398 assert(rem_iface != NULL);
00399
00400
00401 sysarg_t iface_method_idx = IPC_GET_ARG1(call);
00402 remote_iface_func_ptr_t iface_method_ptr =
00403 get_remote_method(rem_iface, iface_method_idx);
00404 if (iface_method_ptr == NULL) {
00405
00406 printf("%s: driver_connection_gen error - "
00407 "invalid interface method "
00408 "(index %" PRIun ").\n",
00409 driver->name, iface_method_idx);
00410 async_answer_0(callid, ENOTSUP);
00411 break;
00412 }
00413
00414
00415
00416
00417
00418
00419
00420 (*iface_method_ptr)(fun, ops, callid, &call);
00421 break;
00422 }
00423 }
00424 }
00425
00426 static void driver_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
00427 {
00428 driver_connection_gen(iid, icall, true);
00429 }
00430
00431 static void driver_connection_client(ipc_callid_t iid, ipc_call_t *icall)
00432 {
00433 driver_connection_gen(iid, icall, false);
00434 }
00435
00437 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall)
00438 {
00439
00440 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
00441 case DRIVER_DEVMAN:
00442
00443 driver_connection_devman(iid, icall);
00444 break;
00445 case DRIVER_DRIVER:
00446
00447 driver_connection_driver(iid, icall);
00448 break;
00449 case DRIVER_CLIENT:
00450
00451 driver_connection_client(iid, icall);
00452 break;
00453 default:
00454
00455 async_answer_0(iid, ENOENT);
00456 }
00457 }
00458
00463 static ddf_dev_t *create_device(void)
00464 {
00465 ddf_dev_t *dev;
00466
00467 dev = malloc(sizeof(ddf_dev_t));
00468 if (dev == NULL)
00469 return NULL;
00470
00471 memset(dev, 0, sizeof(ddf_dev_t));
00472 return dev;
00473 }
00474
00479 static ddf_fun_t *create_function(void)
00480 {
00481 ddf_fun_t *fun;
00482
00483 fun = calloc(1, sizeof(ddf_fun_t));
00484 if (fun == NULL)
00485 return NULL;
00486
00487 init_match_ids(&fun->match_ids);
00488 link_initialize(&fun->link);
00489
00490 return fun;
00491 }
00492
00497 static void delete_device(ddf_dev_t *dev)
00498 {
00499 free(dev);
00500 }
00501
00506 static void delete_function(ddf_fun_t *fun)
00507 {
00508 clean_match_ids(&fun->match_ids);
00509 if (fun->name != NULL)
00510 free(fun->name);
00511 free(fun);
00512 }
00513
00537 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
00538 {
00539 ddf_fun_t *fun;
00540
00541 fun = create_function();
00542 if (fun == NULL)
00543 return NULL;
00544
00545 fun->bound = false;
00546 fun->dev = dev;
00547 fun->ftype = ftype;
00548
00549 fun->name = str_dup(name);
00550 if (fun->name == NULL) {
00551 delete_function(fun);
00552 return NULL;
00553 }
00554
00555 return fun;
00556 }
00557
00565 void ddf_fun_destroy(ddf_fun_t *fun)
00566 {
00567 assert(fun->bound == false);
00568 delete_function(fun);
00569 }
00570
00571 static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx)
00572 {
00573 assert(is_valid_iface_idx(idx));
00574 if (fun->ops == NULL)
00575 return NULL;
00576 return fun->ops->interfaces[idx];
00577 }
00578
00591 int ddf_fun_bind(ddf_fun_t *fun)
00592 {
00593 assert(fun->name != NULL);
00594
00595 int res;
00596
00597 add_to_functions_list(fun);
00598 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
00599 fun->dev->handle, &fun->handle);
00600 if (res != EOK) {
00601 remove_from_functions_list(fun);
00602 return res;
00603 }
00604
00605 fun->bound = true;
00606 return res;
00607 }
00608
00619 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
00620 int match_score)
00621 {
00622 match_id_t *match_id;
00623
00624 assert(fun->bound == false);
00625 assert(fun->ftype == fun_inner);
00626
00627 match_id = create_match_id();
00628 if (match_id == NULL)
00629 return ENOMEM;
00630
00631 match_id->id = match_id_str;
00632 match_id->score = 90;
00633
00634 add_match_id(&fun->match_ids, match_id);
00635 return EOK;
00636 }
00637
00639 static remote_handler_t *function_get_default_handler(ddf_fun_t *fun)
00640 {
00641 if (fun->ops == NULL)
00642 return NULL;
00643 return fun->ops->default_handler;
00644 }
00645
00650 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
00651 {
00652 assert(fun->bound == true);
00653 assert(fun->ftype == fun_exposed);
00654
00655 return devman_add_device_to_class(fun->handle, class_name);
00656 }
00657
00658 int ddf_driver_main(driver_t *drv)
00659 {
00660 int rc;
00661
00662
00663
00664
00665
00666 driver = drv;
00667
00668
00669 init_interrupt_context_list(&interrupt_contexts);
00670
00671
00672 async_set_interrupt_received(driver_irq_handler);
00673
00674
00675
00676
00677
00678 rc = devman_driver_register(driver->name, driver_connection);
00679 if (rc != EOK) {
00680 printf("Error: Failed to register driver with device manager "
00681 "(%s).\n", (rc == EEXISTS) ? "driver already started" :
00682 str_error(rc));
00683
00684 return 1;
00685 }
00686
00687
00688 rc = task_retval(0);
00689 if (rc != EOK)
00690 return 1;
00691
00692 async_manager();
00693
00694
00695 return 0;
00696 }
00697