1/* This file is part of the program psim. 2 3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 20 21#ifndef _DEVICE_C_ 22#define _DEVICE_C_ 23 24#include <stdio.h> 25 26#include "device_table.h" 27#include "cap.h" 28 29#include "events.h" 30#include "psim.h" 31 32#ifdef HAVE_STDLIB_H 33#include <stdlib.h> 34#endif 35 36#ifdef HAVE_STRING_H 37#include <string.h> 38#else 39#ifdef HAVE_STRINGS_H 40#include <strings.h> 41#endif 42#endif 43 44#include <ctype.h> 45 46STATIC_INLINE_DEVICE (void) clean_device_properties(device *); 47 48/* property entries */ 49 50typedef struct _device_property_entry device_property_entry; 51struct _device_property_entry { 52 device_property_entry *next; 53 device_property *value; 54 const void *init_array; 55 unsigned sizeof_init_array; 56}; 57 58 59/* Interrupt edges */ 60 61typedef struct _device_interrupt_edge device_interrupt_edge; 62struct _device_interrupt_edge { 63 int my_port; 64 device *dest; 65 int dest_port; 66 device_interrupt_edge *next; 67 object_disposition disposition; 68}; 69 70STATIC_INLINE_DEVICE\ 71(void) 72attach_device_interrupt_edge(device_interrupt_edge **list, 73 int my_port, 74 device *dest, 75 int dest_port, 76 object_disposition disposition) 77{ 78 device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge); 79 new_edge->my_port = my_port; 80 new_edge->dest = dest; 81 new_edge->dest_port = dest_port; 82 new_edge->next = *list; 83 new_edge->disposition = disposition; 84 *list = new_edge; 85} 86 87STATIC_INLINE_DEVICE\ 88(void) 89detach_device_interrupt_edge(device *me, 90 device_interrupt_edge **list, 91 int my_port, 92 device *dest, 93 int dest_port) 94{ 95 while (*list != NULL) { 96 device_interrupt_edge *old_edge = *list; 97 if (old_edge->dest == dest 98 && old_edge->dest_port == dest_port 99 && old_edge->my_port == my_port) { 100 if (old_edge->disposition == permenant_object) 101 device_error(me, "attempt to delete permenant interrupt"); 102 *list = old_edge->next; 103 free(old_edge); 104 return; 105 } 106 } 107 device_error(me, "attempt to delete unattached interrupt"); 108} 109 110STATIC_INLINE_DEVICE\ 111(void) 112clean_device_interrupt_edges(device_interrupt_edge **list) 113{ 114 while (*list != NULL) { 115 device_interrupt_edge *old_edge = *list; 116 switch (old_edge->disposition) { 117 case permenant_object: 118 list = &old_edge->next; 119 break; 120 case tempoary_object: 121 *list = old_edge->next; 122 free(old_edge); 123 break; 124 } 125 } 126} 127 128 129/* A device */ 130 131struct _device { 132 133 /* my name is ... */ 134 const char *name; 135 device_unit unit_address; 136 const char *path; 137 int nr_address_cells; 138 int nr_size_cells; 139 140 /* device tree */ 141 device *parent; 142 device *children; 143 device *sibling; 144 145 /* its template methods */ 146 void *data; /* device specific data */ 147 const device_callbacks *callback; 148 149 /* device properties */ 150 device_property_entry *properties; 151 152 /* interrupts */ 153 device_interrupt_edge *interrupt_destinations; 154 155 /* any open instances of this device */ 156 device_instance *instances; 157 158 /* the internal/external mappings and other global requirements */ 159 cap *ihandles; 160 cap *phandles; 161 psim *system; 162 163 /* debugging */ 164 int trace; 165}; 166 167 168/* an instance of a device */ 169struct _device_instance { 170 void *data; 171 char *args; 172 char *path; 173 const device_instance_callbacks *callback; 174 /* the root instance */ 175 device *owner; 176 device_instance *next; 177 /* interposed instance */ 178 device_instance *parent; 179 device_instance *child; 180}; 181 182 183 184/* creation */ 185 186STATIC_INLINE_DEVICE\ 187(const char *) 188device_full_name(device *leaf, 189 char *buf, 190 unsigned sizeof_buf) 191{ 192 /* get a buffer */ 193 char full_name[1024]; 194 if (buf == (char*)0) { 195 buf = full_name; 196 sizeof_buf = sizeof(full_name); 197 } 198 199 /* construct a name */ 200 if (leaf->parent == NULL) { 201 if (sizeof_buf < 1) 202 error("device_full_name: buffer overflow"); 203 *buf = '\0'; 204 } 205 else { 206 char unit[1024]; 207 device_full_name(leaf->parent, buf, sizeof_buf); 208 if (leaf->parent != NULL 209 && device_encode_unit(leaf->parent, 210 &leaf->unit_address, 211 unit+1, 212 sizeof(unit)-1) > 0) 213 unit[0] = '@'; 214 else 215 unit[0] = '\0'; 216 if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit) 217 >= sizeof_buf) 218 error("device_full_name: buffer overflow"); 219 strcat(buf, "/"); 220 strcat(buf, leaf->name); 221 strcat (buf, unit); 222 } 223 224 /* return it usefully */ 225 if (buf == full_name) 226 buf = (char *) strdup(full_name); 227 return buf; 228} 229 230STATIC_INLINE_DEVICE\ 231(device *) 232device_create_from(const char *name, 233 const device_unit *unit_address, 234 void *data, 235 const device_callbacks *callbacks, 236 device *parent) 237{ 238 device *new_device = ZALLOC(device); 239 240 /* insert it into the device tree */ 241 new_device->parent = parent; 242 new_device->children = NULL; 243 if (parent != NULL) { 244 device **sibling = &parent->children; 245 while ((*sibling) != NULL) 246 sibling = &(*sibling)->sibling; 247 *sibling = new_device; 248 } 249 250 /* give it a name */ 251 new_device->name = (char *) strdup(name); 252 new_device->unit_address = *unit_address; 253 new_device->path = device_full_name(new_device, NULL, 0); 254 255 /* its template */ 256 new_device->data = data; 257 new_device->callback = callbacks; 258 259 /* its properties - already null */ 260 /* interrupts - already null */ 261 262 /* mappings - if needed */ 263 if (parent == NULL) { 264 new_device->ihandles = cap_create(name); 265 new_device->phandles = cap_create(name); 266 } 267 else { 268 new_device->ihandles = device_root(parent)->ihandles; 269 new_device->phandles = device_root(parent)->phandles; 270 } 271 272 cap_add(new_device->phandles, new_device); 273 return new_device; 274} 275 276 277 278INLINE_DEVICE\ 279(device *) 280device_create(device *parent, 281 const char *base, 282 const char *name, 283 const char *unit_address, 284 const char *args) 285{ 286 const device_descriptor *const *table; 287 for (table = device_table; *table != NULL; table++) { 288 const device_descriptor *descr; 289 for (descr = *table; descr->name != NULL; descr++) { 290 if (strcmp(base, descr->name) == 0) { 291 device_unit address = { 0 }; 292 void *data = NULL; 293 if (parent != NULL) 294 if (device_decode_unit(parent, unit_address, &address) < 0) 295 device_error(parent, "invalid address %s for device %s", 296 unit_address, name); 297 if (descr->creator != NULL) 298 data = descr->creator(name, &address, args); 299 return device_create_from(name, &address, data, 300 descr->callbacks, parent); 301 } 302 } 303 } 304 device_error(parent, "attempt to attach unknown device %s", name); 305 return NULL; 306} 307 308 309 310INLINE_DEVICE\ 311(void) 312device_usage(int verbose) 313{ 314 const device_descriptor *const *table; 315 if (verbose == 1) { 316 int pos = 0; 317 for (table = device_table; *table != NULL; table++) { 318 const device_descriptor *descr; 319 for (descr = *table; descr->name != NULL; descr++) { 320 pos += strlen(descr->name) + 2; 321 if (pos > 75) { 322 pos = strlen(descr->name) + 2; 323 printf_filtered("\n"); 324 } 325 printf_filtered(" %s", descr->name); 326 } 327 printf_filtered("\n"); 328 } 329 } 330 if (verbose > 1) { 331 for (table = device_table; *table != NULL; table++) { 332 const device_descriptor *descr; 333 for (descr = *table; descr->name != NULL; descr++) { 334 printf_filtered(" %s:\n", descr->name); 335 /* interrupt ports */ 336 if (descr->callbacks->interrupt.ports != NULL) { 337 const device_interrupt_port_descriptor *ports = 338 descr->callbacks->interrupt.ports; 339 printf_filtered(" interrupt ports:"); 340 while (ports->name != NULL) { 341 printf_filtered(" %s", ports->name); 342 ports++; 343 } 344 printf_filtered("\n"); 345 } 346 /* general info */ 347 if (descr->callbacks->usage != NULL) 348 descr->callbacks->usage(verbose); 349 } 350 } 351 } 352} 353 354 355 356 357 358/* Device node: */ 359 360INLINE_DEVICE\ 361(device *) 362device_parent(device *me) 363{ 364 return me->parent; 365} 366 367INLINE_DEVICE\ 368(device *) 369device_root(device *me) 370{ 371 ASSERT(me != NULL); 372 while (me->parent != NULL) 373 me = me->parent; 374 return me; 375} 376 377INLINE_DEVICE\ 378(device *) 379device_sibling(device *me) 380{ 381 return me->sibling; 382} 383 384INLINE_DEVICE\ 385(device *) 386device_child(device *me) 387{ 388 return me->children; 389} 390 391INLINE_DEVICE\ 392(const char *) 393device_name(device *me) 394{ 395 return me->name; 396} 397 398INLINE_DEVICE\ 399(const char *) 400device_path(device *me) 401{ 402 return me->path; 403} 404 405INLINE_DEVICE\ 406(void *) 407device_data(device *me) 408{ 409 return me->data; 410} 411 412INLINE_DEVICE\ 413(psim *) 414device_system(device *me) 415{ 416 return me->system; 417} 418 419INLINE_DEVICE\ 420(const device_unit *) 421device_unit_address(device *me) 422{ 423 return &me->unit_address; 424} 425 426 427INLINE_DEVICE\ 428(int) 429device_address_to_attach_address(device *me, 430 const device_unit *address, 431 int *attach_space, 432 unsigned_word *attach_address, 433 device *client) 434{ 435 if (me->callback->convert.address_to_attach_address == NULL) 436 device_error(me, "no convert.address_to_attach_address method"); 437 return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client); 438} 439 440 441INLINE_DEVICE\ 442(int) 443device_size_to_attach_size(device *me, 444 const device_unit *size, 445 unsigned *nr_bytes, 446 device *client) 447{ 448 if (me->callback->convert.size_to_attach_size == NULL) 449 device_error(me, "no convert.size_to_attach_size method"); 450 return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client); 451} 452 453 454INLINE_DEVICE\ 455(int) 456device_decode_unit(device *bus, 457 const char *unit, 458 device_unit *address) 459{ 460 if (bus->callback->convert.decode_unit == NULL) 461 device_error(bus, "no convert.decode_unit method"); 462 return bus->callback->convert.decode_unit(bus, unit, address); 463} 464 465 466INLINE_DEVICE\ 467(int) 468device_encode_unit(device *bus, 469 const device_unit *unit_address, 470 char *buf, 471 int sizeof_buf) 472{ 473 if (bus->callback->convert.encode_unit == NULL) 474 device_error(bus, "no convert.encode_unit method"); 475 return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf); 476} 477 478INLINE_DEVICE\ 479(unsigned) 480device_nr_address_cells(device *me) 481{ 482 if (me->nr_address_cells == 0) { 483 if (device_find_property(me, "#address-cells") != NULL) 484 me->nr_address_cells = device_find_integer_property(me, "#address-cells"); 485 else 486 me->nr_address_cells = 2; 487 } 488 return me->nr_address_cells; 489} 490 491INLINE_DEVICE\ 492(unsigned) 493device_nr_size_cells(device *me) 494{ 495 if (me->nr_size_cells == 0) { 496 if (device_find_property(me, "#size-cells") != NULL) 497 me->nr_size_cells = device_find_integer_property(me, "#size-cells"); 498 else 499 me->nr_size_cells = 1; 500 } 501 return me->nr_size_cells; 502} 503 504 505 506/* device-instance: */ 507 508INLINE_DEVICE\ 509(device_instance *) 510device_create_instance_from(device *me, 511 device_instance *parent, 512 void *data, 513 const char *path, 514 const char *args, 515 const device_instance_callbacks *callbacks) 516{ 517 device_instance *instance = ZALLOC(device_instance); 518 if ((me == NULL) == (parent == NULL)) 519 device_error(me, "can't have both parent instance and parent device"); 520 /*instance->unit*/ 521 /* link this instance into the devices list */ 522 if (me != NULL) { 523 ASSERT(parent == NULL); 524 instance->owner = me; 525 instance->parent = NULL; 526 /* link this instance into the front of the devices instance list */ 527 instance->next = me->instances; 528 me->instances = instance; 529 } 530 if (parent != NULL) { 531 device_instance **previous; 532 ASSERT(parent->child == NULL); 533 parent->child = instance; 534 ASSERT(me == NULL); 535 instance->owner = parent->owner; 536 instance->parent = parent; 537 /* in the devices instance list replace the parent instance with 538 this one */ 539 instance->next = parent->next; 540 /* replace parent with this new node */ 541 previous = &instance->owner->instances; 542 while (*previous != parent) { 543 ASSERT(*previous != NULL); 544 previous = &(*previous)->next; 545 } 546 *previous = instance; 547 } 548 instance->data = data; 549 instance->args = (args == NULL ? NULL : (char *) strdup(args)); 550 instance->path = (path == NULL ? NULL : (char *) strdup(path)); 551 instance->callback = callbacks; 552 cap_add(instance->owner->ihandles, instance); 553 return instance; 554} 555 556 557INLINE_DEVICE\ 558(device_instance *) 559device_create_instance(device *me, 560 const char *path, 561 const char *args) 562{ 563 /* create the instance */ 564 if (me->callback->instance_create == NULL) 565 device_error(me, "no instance_create method"); 566 return me->callback->instance_create(me, path, args); 567} 568 569 570STATIC_INLINE_DEVICE\ 571(void) 572clean_device_instances(device *me) 573{ 574 device_instance **instance = &me->instances; 575 while (*instance != NULL) { 576 device_instance *old_instance = *instance; 577 device_instance_delete(old_instance); 578 instance = &me->instances; 579 } 580} 581 582 583INLINE_DEVICE\ 584(void) 585device_instance_delete(device_instance *instance) 586{ 587 device *me = instance->owner; 588 if (instance->callback->delete == NULL) 589 device_error(me, "no delete method"); 590 instance->callback->delete(instance); 591 if (instance->args != NULL) 592 free(instance->args); 593 if (instance->path != NULL) 594 free(instance->path); 595 if (instance->child == NULL) { 596 /* only remove leaf nodes */ 597 device_instance **curr = &me->instances; 598 while (*curr != instance) { 599 ASSERT(*curr != NULL); 600 curr = &(*curr)->next; 601 } 602 *curr = instance->next; 603 } 604 else { 605 /* check it isn't in the instance list */ 606 device_instance *curr = me->instances; 607 while (curr != NULL) { 608 ASSERT(curr != instance); 609 curr = curr->next; 610 } 611 /* unlink the child */ 612 ASSERT(instance->child->parent == instance); 613 instance->child->parent = NULL; 614 } 615 cap_remove(me->ihandles, instance); 616 free(instance); 617} 618 619INLINE_DEVICE\ 620(int) 621device_instance_read(device_instance *instance, 622 void *addr, 623 unsigned_word len) 624{ 625 device *me = instance->owner; 626 if (instance->callback->read == NULL) 627 device_error(me, "no read method"); 628 return instance->callback->read(instance, addr, len); 629} 630 631INLINE_DEVICE\ 632(int) 633device_instance_write(device_instance *instance, 634 const void *addr, 635 unsigned_word len) 636{ 637 device *me = instance->owner; 638 if (instance->callback->write == NULL) 639 device_error(me, "no write method"); 640 return instance->callback->write(instance, addr, len); 641} 642 643INLINE_DEVICE\ 644(int) 645device_instance_seek(device_instance *instance, 646 unsigned_word pos_hi, 647 unsigned_word pos_lo) 648{ 649 device *me = instance->owner; 650 if (instance->callback->seek == NULL) 651 device_error(me, "no seek method"); 652 return instance->callback->seek(instance, pos_hi, pos_lo); 653} 654 655INLINE_DEVICE\ 656(int) 657device_instance_call_method(device_instance *instance, 658 const char *method_name, 659 int n_stack_args, 660 unsigned_cell stack_args[/*n_stack_args*/], 661 int n_stack_returns, 662 unsigned_cell stack_returns[/*n_stack_args*/]) 663{ 664 device *me = instance->owner; 665 const device_instance_methods *method = instance->callback->methods; 666 if (method == NULL) { 667 device_error(me, "no methods (want %s)", method_name); 668 } 669 while (method->name != NULL) { 670 if (strcmp(method->name, method_name) == 0) { 671 return method->method(instance, 672 n_stack_args, stack_args, 673 n_stack_returns, stack_returns); 674 } 675 method++; 676 } 677 device_error(me, "no %s method", method_name); 678 return 0; 679} 680 681 682INLINE_DEVICE\ 683(device *) 684device_instance_device(device_instance *instance) 685{ 686 return instance->owner; 687} 688 689INLINE_DEVICE\ 690(const char *) 691device_instance_path(device_instance *instance) 692{ 693 return instance->path; 694} 695 696INLINE_DEVICE\ 697(void *) 698device_instance_data(device_instance *instance) 699{ 700 return instance->data; 701} 702 703 704 705/* Device Properties: */ 706 707STATIC_INLINE_DEVICE\ 708(device_property_entry *) 709find_property_entry(device *me, 710 const char *property) 711{ 712 device_property_entry *entry; 713 ASSERT(property != NULL); 714 entry = me->properties; 715 while (entry != NULL) { 716 if (strcmp(entry->value->name, property) == 0) 717 return entry; 718 entry = entry->next; 719 } 720 return NULL; 721} 722 723STATIC_INLINE_DEVICE\ 724(void) 725device_add_property(device *me, 726 const char *property, 727 device_property_type type, 728 const void *init_array, 729 unsigned sizeof_init_array, 730 const void *array, 731 unsigned sizeof_array, 732 const device_property *original, 733 object_disposition disposition) 734{ 735 device_property_entry *new_entry = NULL; 736 device_property *new_value = NULL; 737 738 /* find the list end */ 739 device_property_entry **insertion_point = &me->properties; 740 while (*insertion_point != NULL) { 741 if (strcmp((*insertion_point)->value->name, property) == 0) 742 return; 743 insertion_point = &(*insertion_point)->next; 744 } 745 746 /* create a new value */ 747 new_value = ZALLOC(device_property); 748 new_value->name = (char *) strdup(property); 749 new_value->type = type; 750 if (sizeof_array > 0) { 751 void *new_array = zalloc(sizeof_array); 752 memcpy(new_array, array, sizeof_array); 753 new_value->array = new_array; 754 new_value->sizeof_array = sizeof_array; 755 } 756 new_value->owner = me; 757 new_value->original = original; 758 new_value->disposition = disposition; 759 760 /* insert the value into the list */ 761 new_entry = ZALLOC(device_property_entry); 762 *insertion_point = new_entry; 763 if (sizeof_init_array > 0) { 764 void *new_init_array = zalloc(sizeof_init_array); 765 memcpy(new_init_array, init_array, sizeof_init_array); 766 new_entry->init_array = new_init_array; 767 new_entry->sizeof_init_array = sizeof_init_array; 768 } 769 new_entry->value = new_value; 770} 771 772 773/* local - not available externally */ 774STATIC_INLINE_DEVICE\ 775(void) 776device_set_property(device *me, 777 const char *property, 778 device_property_type type, 779 const void *array, 780 int sizeof_array) 781{ 782 /* find the property */ 783 device_property_entry *entry = find_property_entry(me, property); 784 if (entry != NULL) { 785 /* existing property - update it */ 786 void *new_array = 0; 787 device_property *value = entry->value; 788 /* check the type matches */ 789 if (value->type != type) 790 device_error(me, "conflict between type of new and old value for property %s", property); 791 /* replace its value */ 792 if (value->array != NULL) 793 free((void*)value->array); 794 new_array = (sizeof_array > 0 795 ? zalloc(sizeof_array) 796 : (void*)0); 797 value->array = new_array; 798 value->sizeof_array = sizeof_array; 799 if (sizeof_array > 0) 800 memcpy(new_array, array, sizeof_array); 801 return; 802 } 803 else { 804 /* new property - create it */ 805 device_add_property(me, property, type, 806 NULL, 0, array, sizeof_array, 807 NULL, tempoary_object); 808 } 809} 810 811 812STATIC_INLINE_DEVICE\ 813(void) 814clean_device_properties(device *me) 815{ 816 device_property_entry **delete_point = &me->properties; 817 while (*delete_point != NULL) { 818 device_property_entry *current = *delete_point; 819 switch (current->value->disposition) { 820 case permenant_object: 821 /* zap the current value, will be initialized later */ 822 ASSERT(current->init_array != NULL); 823 if (current->value->array != NULL) { 824 free((void*)current->value->array); 825 current->value->array = NULL; 826 } 827 delete_point = &(*delete_point)->next; 828 break; 829 case tempoary_object: 830 /* zap the actual property, was created during simulation run */ 831 ASSERT(current->init_array == NULL); 832 *delete_point = current->next; 833 if (current->value->array != NULL) 834 free((void*)current->value->array); 835 free(current->value); 836 free(current); 837 break; 838 } 839 } 840} 841 842 843INLINE_DEVICE\ 844(void) 845device_init_static_properties(device *me, 846 void *data) 847{ 848 device_property_entry *property; 849 for (property = me->properties; 850 property != NULL; 851 property = property->next) { 852 ASSERT(property->init_array != NULL); 853 ASSERT(property->value->array == NULL); 854 ASSERT(property->value->disposition == permenant_object); 855 switch (property->value->type) { 856 case array_property: 857 case boolean_property: 858 case range_array_property: 859 case reg_array_property: 860 case string_property: 861 case string_array_property: 862 case integer_property: 863 /* delete the property, and replace it with the original */ 864 device_set_property(me, property->value->name, 865 property->value->type, 866 property->init_array, 867 property->sizeof_init_array); 868 break; 869 case ihandle_property: 870 break; 871 } 872 } 873} 874 875 876INLINE_DEVICE\ 877(void) 878device_init_runtime_properties(device *me, 879 void *data) 880{ 881 device_property_entry *property; 882 for (property = me->properties; 883 property != NULL; 884 property = property->next) { 885 switch (property->value->disposition) { 886 case permenant_object: 887 switch (property->value->type) { 888 case ihandle_property: 889 { 890 device_instance *ihandle; 891 ihandle_runtime_property_spec spec; 892 ASSERT(property->init_array != NULL); 893 ASSERT(property->value->array == NULL); 894 device_find_ihandle_runtime_property(me, property->value->name, &spec); 895 ihandle = tree_instance(me, spec.full_path); 896 device_set_ihandle_property(me, property->value->name, ihandle); 897 break; 898 } 899 case array_property: 900 case boolean_property: 901 case range_array_property: 902 case integer_property: 903 case reg_array_property: 904 case string_property: 905 case string_array_property: 906 ASSERT(property->init_array != NULL); 907 ASSERT(property->value->array != NULL); 908 break; 909 } 910 break; 911 case tempoary_object: 912 ASSERT(property->init_array == NULL); 913 ASSERT(property->value->array != NULL); 914 break; 915 } 916 } 917} 918 919 920INLINE_DEVICE\ 921(const device_property *) 922device_next_property(const device_property *property) 923{ 924 /* find the property in the list */ 925 device *owner = property->owner; 926 device_property_entry *entry = owner->properties; 927 while (entry != NULL && entry->value != property) 928 entry = entry->next; 929 /* now return the following property */ 930 ASSERT(entry != NULL); /* must be a member! */ 931 if (entry->next != NULL) 932 return entry->next->value; 933 else 934 return NULL; 935} 936 937 938INLINE_DEVICE\ 939(const device_property *) 940device_find_property(device *me, 941 const char *property) 942{ 943 if (me == NULL) { 944 return NULL; 945 } 946 else if (property == NULL || strcmp(property, "") == 0) { 947 if (me->properties == NULL) 948 return NULL; 949 else 950 return me->properties->value; 951 } 952 else { 953 device_property_entry *entry = find_property_entry(me, property); 954 if (entry != NULL) 955 return entry->value; 956 } 957 return NULL; 958} 959 960 961INLINE_DEVICE\ 962(void) 963device_add_array_property(device *me, 964 const char *property, 965 const void *array, 966 int sizeof_array) 967{ 968 device_add_property(me, property, array_property, 969 array, sizeof_array, array, sizeof_array, 970 NULL, permenant_object); 971} 972 973INLINE_DEVICE\ 974(void) 975device_set_array_property(device *me, 976 const char *property, 977 const void *array, 978 int sizeof_array) 979{ 980 device_set_property(me, property, array_property, array, sizeof_array); 981} 982 983INLINE_DEVICE\ 984(const device_property *) 985device_find_array_property(device *me, 986 const char *property) 987{ 988 const device_property *node; 989 node = device_find_property(me, property); 990 if (node == (device_property*)0 991 || node->type != array_property) 992 device_error(me, "property %s not found or of wrong type", property); 993 return node; 994} 995 996 997INLINE_DEVICE\ 998(void) 999device_add_boolean_property(device *me, 1000 const char *property, 1001 int boolean) 1002{ 1003 signed32 new_boolean = (boolean ? -1 : 0); 1004 device_add_property(me, property, boolean_property, 1005 &new_boolean, sizeof(new_boolean), 1006 &new_boolean, sizeof(new_boolean), 1007 NULL, permenant_object); 1008} 1009 1010INLINE_DEVICE\ 1011(int) 1012device_find_boolean_property(device *me, 1013 const char *property) 1014{ 1015 const device_property *node; 1016 unsigned_cell boolean; 1017 node = device_find_property(me, property); 1018 if (node == (device_property*)0 1019 || node->type != boolean_property) 1020 device_error(me, "property %s not found or of wrong type", property); 1021 ASSERT(sizeof(boolean) == node->sizeof_array); 1022 memcpy(&boolean, node->array, sizeof(boolean)); 1023 return boolean; 1024} 1025 1026 1027INLINE_DEVICE\ 1028(void) 1029device_add_ihandle_runtime_property(device *me, 1030 const char *property, 1031 const ihandle_runtime_property_spec *ihandle) 1032{ 1033 /* enter the full path as the init array */ 1034 device_add_property(me, property, ihandle_property, 1035 ihandle->full_path, strlen(ihandle->full_path) + 1, 1036 NULL, 0, 1037 NULL, permenant_object); 1038} 1039 1040INLINE_DEVICE\ 1041(void) 1042device_find_ihandle_runtime_property(device *me, 1043 const char *property, 1044 ihandle_runtime_property_spec *ihandle) 1045{ 1046 device_property_entry *entry = find_property_entry(me, property); 1047 TRACE(trace_devices, 1048 ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n", 1049 (long)me, property)); 1050 if (entry == NULL 1051 || entry->value->type != ihandle_property 1052 || entry->value->disposition != permenant_object) 1053 device_error(me, "property %s not found or of wrong type", property); 1054 ASSERT(entry->init_array != NULL); 1055 /* the full path */ 1056 ihandle->full_path = entry->init_array; 1057} 1058 1059 1060 1061INLINE_DEVICE\ 1062(void) 1063device_set_ihandle_property(device *me, 1064 const char *property, 1065 device_instance *ihandle) 1066{ 1067 unsigned_cell cells; 1068 cells = H2BE_cell(device_instance_to_external(ihandle)); 1069 device_set_property(me, property, ihandle_property, 1070 &cells, sizeof(cells)); 1071 1072} 1073 1074INLINE_DEVICE\ 1075(device_instance *) 1076device_find_ihandle_property(device *me, 1077 const char *property) 1078{ 1079 const device_property *node; 1080 unsigned_cell ihandle; 1081 device_instance *instance; 1082 1083 node = device_find_property(me, property); 1084 if (node == NULL || node->type != ihandle_property) 1085 device_error(me, "property %s not found or of wrong type", property); 1086 if (node->array == NULL) 1087 device_error(me, "runtime property %s not yet initialized", property); 1088 1089 ASSERT(sizeof(ihandle) == node->sizeof_array); 1090 memcpy(&ihandle, node->array, sizeof(ihandle)); 1091 instance = external_to_device_instance(me, BE2H_cell(ihandle)); 1092 ASSERT(instance != NULL); 1093 return instance; 1094} 1095 1096 1097INLINE_DEVICE\ 1098(void) 1099device_add_integer_property(device *me, 1100 const char *property, 1101 signed_cell integer) 1102{ 1103 H2BE(integer); 1104 device_add_property(me, property, integer_property, 1105 &integer, sizeof(integer), 1106 &integer, sizeof(integer), 1107 NULL, permenant_object); 1108} 1109 1110INLINE_DEVICE\ 1111(signed_cell) 1112device_find_integer_property(device *me, 1113 const char *property) 1114{ 1115 const device_property *node; 1116 signed_cell integer; 1117 TRACE(trace_devices, 1118 ("device_find_integer(me=0x%lx, property=%s)\n", 1119 (long)me, property)); 1120 node = device_find_property(me, property); 1121 if (node == (device_property*)0 1122 || node->type != integer_property) 1123 device_error(me, "property %s not found or of wrong type", property); 1124 ASSERT(sizeof(integer) == node->sizeof_array); 1125 memcpy(&integer, node->array, sizeof(integer)); 1126 return BE2H_cell(integer); 1127} 1128 1129INLINE_DEVICE\ 1130(int) 1131device_find_integer_array_property(device *me, 1132 const char *property, 1133 unsigned index, 1134 signed_cell *integer) 1135{ 1136 const device_property *node; 1137 int sizeof_integer = sizeof(*integer); 1138 signed_cell *cell; 1139 TRACE(trace_devices, 1140 ("device_find_integer(me=0x%lx, property=%s)\n", 1141 (long)me, property)); 1142 1143 /* check things sane */ 1144 node = device_find_property(me, property); 1145 if (node == (device_property*)0 1146 || (node->type != integer_property 1147 && node->type != array_property)) 1148 device_error(me, "property %s not found or of wrong type", property); 1149 if ((node->sizeof_array % sizeof_integer) != 0) 1150 device_error(me, "property %s contains an incomplete number of cells", property); 1151 if (node->sizeof_array <= sizeof_integer * index) 1152 return 0; 1153 1154 /* Find and convert the value */ 1155 cell = ((signed_cell*)node->array) + index; 1156 *integer = BE2H_cell(*cell); 1157 1158 return node->sizeof_array / sizeof_integer; 1159} 1160 1161 1162STATIC_INLINE_DEVICE\ 1163(unsigned_cell *) 1164unit_address_to_cells(const device_unit *unit, 1165 unsigned_cell *cell, 1166 int nr_cells) 1167{ 1168 int i; 1169 ASSERT(nr_cells == unit->nr_cells); 1170 for (i = 0; i < unit->nr_cells; i++) { 1171 *cell = H2BE_cell(unit->cells[i]); 1172 cell += 1; 1173 } 1174 return cell; 1175} 1176 1177 1178STATIC_INLINE_DEVICE\ 1179(const unsigned_cell *) 1180cells_to_unit_address(const unsigned_cell *cell, 1181 device_unit *unit, 1182 int nr_cells) 1183{ 1184 int i; 1185 memset(unit, 0, sizeof(*unit)); 1186 unit->nr_cells = nr_cells; 1187 for (i = 0; i < unit->nr_cells; i++) { 1188 unit->cells[i] = BE2H_cell(*cell); 1189 cell += 1; 1190 } 1191 return cell; 1192} 1193 1194 1195STATIC_INLINE_DEVICE\ 1196(unsigned) 1197nr_range_property_cells(device *me, 1198 int nr_ranges) 1199{ 1200 return ((device_nr_address_cells(me) 1201 + device_nr_address_cells(device_parent(me)) 1202 + device_nr_size_cells(me)) 1203 ) * nr_ranges; 1204} 1205 1206INLINE_DEVICE\ 1207(void) 1208device_add_range_array_property(device *me, 1209 const char *property, 1210 const range_property_spec *ranges, 1211 unsigned nr_ranges) 1212{ 1213 unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges) 1214 * sizeof(unsigned_cell)); 1215 unsigned_cell *cells = zalloc(sizeof_cells); 1216 unsigned_cell *cell; 1217 int i; 1218 1219 /* copy the property elements over */ 1220 cell = cells; 1221 for (i = 0; i < nr_ranges; i++) { 1222 const range_property_spec *range = &ranges[i]; 1223 /* copy the child address */ 1224 cell = unit_address_to_cells(&range->child_address, cell, 1225 device_nr_address_cells(me)); 1226 /* copy the parent address */ 1227 cell = unit_address_to_cells(&range->parent_address, cell, 1228 device_nr_address_cells(device_parent(me))); 1229 /* copy the size */ 1230 cell = unit_address_to_cells(&range->size, cell, 1231 device_nr_size_cells(me)); 1232 } 1233 ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]); 1234 1235 /* add it */ 1236 device_add_property(me, property, range_array_property, 1237 cells, sizeof_cells, 1238 cells, sizeof_cells, 1239 NULL, permenant_object); 1240 1241 free(cells); 1242} 1243 1244INLINE_DEVICE\ 1245(int) 1246device_find_range_array_property(device *me, 1247 const char *property, 1248 unsigned index, 1249 range_property_spec *range) 1250{ 1251 const device_property *node; 1252 unsigned sizeof_entry = (nr_range_property_cells(me, 1) 1253 * sizeof(unsigned_cell)); 1254 const unsigned_cell *cells; 1255 1256 /* locate the property */ 1257 node = device_find_property(me, property); 1258 if (node == (device_property*)0 1259 || node->type != range_array_property) 1260 device_error(me, "property %s not found or of wrong type", property); 1261 1262 /* aligned ? */ 1263 if ((node->sizeof_array % sizeof_entry) != 0) 1264 device_error(me, "property %s contains an incomplete number of entries", 1265 property); 1266 1267 /* within bounds? */ 1268 if (node->sizeof_array < sizeof_entry * (index + 1)) 1269 return 0; 1270 1271 /* find the range of interest */ 1272 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 1273 1274 /* copy the child address out - converting as we go */ 1275 cells = cells_to_unit_address(cells, &range->child_address, 1276 device_nr_address_cells(me)); 1277 1278 /* copy the parent address out - converting as we go */ 1279 cells = cells_to_unit_address(cells, &range->parent_address, 1280 device_nr_address_cells(device_parent(me))); 1281 1282 /* copy the size - converting as we go */ 1283 cells = cells_to_unit_address(cells, &range->size, 1284 device_nr_size_cells(me)); 1285 1286 return node->sizeof_array / sizeof_entry; 1287} 1288 1289 1290STATIC_INLINE_DEVICE\ 1291(unsigned) 1292nr_reg_property_cells(device *me, 1293 int nr_regs) 1294{ 1295 return (device_nr_address_cells(device_parent(me)) 1296 + device_nr_size_cells(device_parent(me)) 1297 ) * nr_regs; 1298} 1299 1300INLINE_DEVICE\ 1301(void) 1302device_add_reg_array_property(device *me, 1303 const char *property, 1304 const reg_property_spec *regs, 1305 unsigned nr_regs) 1306{ 1307 unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs) 1308 * sizeof(unsigned_cell)); 1309 unsigned_cell *cells = zalloc(sizeof_cells); 1310 unsigned_cell *cell; 1311 int i; 1312 1313 /* copy the property elements over */ 1314 cell = cells; 1315 for (i = 0; i < nr_regs; i++) { 1316 const reg_property_spec *reg = ®s[i]; 1317 /* copy the address */ 1318 cell = unit_address_to_cells(®->address, cell, 1319 device_nr_address_cells(device_parent(me))); 1320 /* copy the size */ 1321 cell = unit_address_to_cells(®->size, cell, 1322 device_nr_size_cells(device_parent(me))); 1323 } 1324 ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]); 1325 1326 /* add it */ 1327 device_add_property(me, property, reg_array_property, 1328 cells, sizeof_cells, 1329 cells, sizeof_cells, 1330 NULL, permenant_object); 1331 1332 free(cells); 1333} 1334 1335INLINE_DEVICE\ 1336(int) 1337device_find_reg_array_property(device *me, 1338 const char *property, 1339 unsigned index, 1340 reg_property_spec *reg) 1341{ 1342 const device_property *node; 1343 unsigned sizeof_entry = (nr_reg_property_cells(me, 1) 1344 * sizeof(unsigned_cell)); 1345 const unsigned_cell *cells; 1346 1347 /* locate the property */ 1348 node = device_find_property(me, property); 1349 if (node == (device_property*)0 1350 || node->type != reg_array_property) 1351 device_error(me, "property %s not found or of wrong type", property); 1352 1353 /* aligned ? */ 1354 if ((node->sizeof_array % sizeof_entry) != 0) 1355 device_error(me, "property %s contains an incomplete number of entries", 1356 property); 1357 1358 /* within bounds? */ 1359 if (node->sizeof_array < sizeof_entry * (index + 1)) 1360 return 0; 1361 1362 /* find the range of interest */ 1363 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 1364 1365 /* copy the address out - converting as we go */ 1366 cells = cells_to_unit_address(cells, ®->address, 1367 device_nr_address_cells(device_parent(me))); 1368 1369 /* copy the size out - converting as we go */ 1370 cells = cells_to_unit_address(cells, ®->size, 1371 device_nr_size_cells(device_parent(me))); 1372 1373 return node->sizeof_array / sizeof_entry; 1374} 1375 1376 1377INLINE_DEVICE\ 1378(void) 1379device_add_string_property(device *me, 1380 const char *property, 1381 const char *string) 1382{ 1383 device_add_property(me, property, string_property, 1384 string, strlen(string) + 1, 1385 string, strlen(string) + 1, 1386 NULL, permenant_object); 1387} 1388 1389INLINE_DEVICE\ 1390(const char *) 1391device_find_string_property(device *me, 1392 const char *property) 1393{ 1394 const device_property *node; 1395 const char *string; 1396 node = device_find_property(me, property); 1397 if (node == (device_property*)0 1398 || node->type != string_property) 1399 device_error(me, "property %s not found or of wrong type", property); 1400 string = node->array; 1401 ASSERT(strlen(string) + 1 == node->sizeof_array); 1402 return string; 1403} 1404 1405INLINE_DEVICE\ 1406(void) 1407device_add_string_array_property(device *me, 1408 const char *property, 1409 const string_property_spec *strings, 1410 unsigned nr_strings) 1411{ 1412 int sizeof_array; 1413 int string_nr; 1414 char *array; 1415 char *chp; 1416 if (nr_strings == 0) 1417 device_error(me, "property %s must be non-null", property); 1418 /* total up the size of the needed array */ 1419 for (sizeof_array = 0, string_nr = 0; 1420 string_nr < nr_strings; 1421 string_nr ++) { 1422 sizeof_array += strlen(strings[string_nr]) + 1; 1423 } 1424 /* create the array */ 1425 array = (char*)zalloc(sizeof_array); 1426 chp = array; 1427 for (string_nr = 0; 1428 string_nr < nr_strings; 1429 string_nr++) { 1430 strcpy(chp, strings[string_nr]); 1431 chp += strlen(chp) + 1; 1432 } 1433 ASSERT(chp == array + sizeof_array); 1434 /* now enter it */ 1435 device_add_property(me, property, string_array_property, 1436 array, sizeof_array, 1437 array, sizeof_array, 1438 NULL, permenant_object); 1439} 1440 1441INLINE_DEVICE\ 1442(int) 1443device_find_string_array_property(device *me, 1444 const char *property, 1445 unsigned index, 1446 string_property_spec *string) 1447{ 1448 const device_property *node; 1449 node = device_find_property(me, property); 1450 if (node == (device_property*)0) 1451 device_error(me, "property %s not found", property); 1452 switch (node->type) { 1453 default: 1454 device_error(me, "property %s of wrong type", property); 1455 break; 1456 case string_property: 1457 if (index == 0) { 1458 *string = node->array; 1459 ASSERT(strlen(*string) + 1 == node->sizeof_array); 1460 return 1; 1461 } 1462 break; 1463 case array_property: 1464 if (node->sizeof_array == 0 1465 || ((char*)node->array)[node->sizeof_array - 1] != '\0') 1466 device_error(me, "property %s invalid for string array", property); 1467 /* FALL THROUGH */ 1468 case string_array_property: 1469 ASSERT(node->sizeof_array > 0); 1470 ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0'); 1471 { 1472 const char *chp = node->array; 1473 int nr_entries = 0; 1474 /* count the number of strings, keeping an eye out for the one 1475 we're looking for */ 1476 *string = chp; 1477 do { 1478 if (*chp == '\0') { 1479 /* next string */ 1480 nr_entries++; 1481 chp++; 1482 if (nr_entries == index) 1483 *string = chp; 1484 } 1485 else { 1486 chp++; 1487 } 1488 } while (chp < (char*)node->array + node->sizeof_array); 1489 if (index < nr_entries) 1490 return nr_entries; 1491 else { 1492 *string = NULL; 1493 return 0; 1494 } 1495 } 1496 break; 1497 } 1498 return 0; 1499} 1500 1501INLINE_DEVICE\ 1502(void) 1503device_add_duplicate_property(device *me, 1504 const char *property, 1505 const device_property *original) 1506{ 1507 device_property_entry *master; 1508 TRACE(trace_devices, 1509 ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n", 1510 (long)me, property)); 1511 if (original->disposition != permenant_object) 1512 device_error(me, "Can only duplicate permenant objects"); 1513 /* find the original's master */ 1514 master = original->owner->properties; 1515 while (master->value != original) { 1516 master = master->next; 1517 ASSERT(master != NULL); 1518 } 1519 /* now duplicate it */ 1520 device_add_property(me, property, 1521 original->type, 1522 master->init_array, master->sizeof_init_array, 1523 original->array, original->sizeof_array, 1524 original, permenant_object); 1525} 1526 1527 1528 1529/* Device Hardware: */ 1530 1531INLINE_DEVICE\ 1532(unsigned) 1533device_io_read_buffer(device *me, 1534 void *dest, 1535 int space, 1536 unsigned_word addr, 1537 unsigned nr_bytes, 1538 cpu *processor, 1539 unsigned_word cia) 1540{ 1541 if (me->callback->io.read_buffer == NULL) 1542 device_error(me, "no io.read_buffer method"); 1543 return me->callback->io.read_buffer(me, dest, space, 1544 addr, nr_bytes, 1545 processor, cia); 1546} 1547 1548INLINE_DEVICE\ 1549(unsigned) 1550device_io_write_buffer(device *me, 1551 const void *source, 1552 int space, 1553 unsigned_word addr, 1554 unsigned nr_bytes, 1555 cpu *processor, 1556 unsigned_word cia) 1557{ 1558 if (me->callback->io.write_buffer == NULL) 1559 device_error(me, "no io.write_buffer method"); 1560 return me->callback->io.write_buffer(me, source, space, 1561 addr, nr_bytes, 1562 processor, cia); 1563} 1564 1565INLINE_DEVICE\ 1566(unsigned) 1567device_dma_read_buffer(device *me, 1568 void *dest, 1569 int space, 1570 unsigned_word addr, 1571 unsigned nr_bytes) 1572{ 1573 if (me->callback->dma.read_buffer == NULL) 1574 device_error(me, "no dma.read_buffer method"); 1575 return me->callback->dma.read_buffer(me, dest, space, 1576 addr, nr_bytes); 1577} 1578 1579INLINE_DEVICE\ 1580(unsigned) 1581device_dma_write_buffer(device *me, 1582 const void *source, 1583 int space, 1584 unsigned_word addr, 1585 unsigned nr_bytes, 1586 int violate_read_only_section) 1587{ 1588 if (me->callback->dma.write_buffer == NULL) 1589 device_error(me, "no dma.write_buffer method"); 1590 return me->callback->dma.write_buffer(me, source, space, 1591 addr, nr_bytes, 1592 violate_read_only_section); 1593} 1594 1595INLINE_DEVICE\ 1596(void) 1597device_attach_address(device *me, 1598 attach_type attach, 1599 int space, 1600 unsigned_word addr, 1601 unsigned nr_bytes, 1602 access_type access, 1603 device *client) /*callback/default*/ 1604{ 1605 if (me->callback->address.attach == NULL) 1606 device_error(me, "no address.attach method"); 1607 me->callback->address.attach(me, attach, space, 1608 addr, nr_bytes, access, client); 1609} 1610 1611INLINE_DEVICE\ 1612(void) 1613device_detach_address(device *me, 1614 attach_type attach, 1615 int space, 1616 unsigned_word addr, 1617 unsigned nr_bytes, 1618 access_type access, 1619 device *client) /*callback/default*/ 1620{ 1621 if (me->callback->address.detach == NULL) 1622 device_error(me, "no address.detach method"); 1623 me->callback->address.detach(me, attach, space, 1624 addr, nr_bytes, access, client); 1625} 1626 1627 1628 1629/* Interrupts: */ 1630 1631INLINE_DEVICE(void) 1632device_interrupt_event(device *me, 1633 int my_port, 1634 int level, 1635 cpu *processor, 1636 unsigned_word cia) 1637{ 1638 int found_an_edge = 0; 1639 device_interrupt_edge *edge; 1640 /* device's interrupt lines directly connected */ 1641 for (edge = me->interrupt_destinations; 1642 edge != NULL; 1643 edge = edge->next) { 1644 if (edge->my_port == my_port) { 1645 if (edge->dest->callback->interrupt.event == NULL) 1646 device_error(me, "no interrupt method"); 1647 edge->dest->callback->interrupt.event(edge->dest, 1648 edge->dest_port, 1649 me, 1650 my_port, 1651 level, 1652 processor, cia); 1653 found_an_edge = 1; 1654 } 1655 } 1656 if (!found_an_edge) { 1657 device_error(me, "No interrupt edge for port %d", my_port); 1658 } 1659} 1660 1661INLINE_DEVICE\ 1662(void) 1663device_interrupt_attach(device *me, 1664 int my_port, 1665 device *dest, 1666 int dest_port, 1667 object_disposition disposition) 1668{ 1669 attach_device_interrupt_edge(&me->interrupt_destinations, 1670 my_port, 1671 dest, 1672 dest_port, 1673 disposition); 1674} 1675 1676INLINE_DEVICE\ 1677(void) 1678device_interrupt_detach(device *me, 1679 int my_port, 1680 device *dest, 1681 int dest_port) 1682{ 1683 detach_device_interrupt_edge(me, 1684 &me->interrupt_destinations, 1685 my_port, 1686 dest, 1687 dest_port); 1688} 1689 1690INLINE_DEVICE\ 1691(void) 1692device_interrupt_traverse(device *me, 1693 device_interrupt_traverse_function *handler, 1694 void *data) 1695{ 1696 device_interrupt_edge *interrupt_edge; 1697 for (interrupt_edge = me->interrupt_destinations; 1698 interrupt_edge != NULL; 1699 interrupt_edge = interrupt_edge->next) { 1700 handler(me, interrupt_edge->my_port, 1701 interrupt_edge->dest, interrupt_edge->dest_port, 1702 data); 1703 } 1704} 1705 1706INLINE_DEVICE\ 1707(int) 1708device_interrupt_decode(device *me, 1709 const char *port_name, 1710 port_direction direction) 1711{ 1712 if (port_name == NULL || port_name[0] == '\0') 1713 return 0; 1714 if (isdigit(port_name[0])) { 1715 return strtoul(port_name, NULL, 0); 1716 } 1717 else { 1718 const device_interrupt_port_descriptor *ports = 1719 me->callback->interrupt.ports; 1720 if (ports != NULL) { 1721 while (ports->name != NULL) { 1722 if (ports->direction == bidirect_port 1723 || ports->direction == direction) { 1724 if (ports->nr_ports > 0) { 1725 int len = strlen(ports->name); 1726 if (strncmp(port_name, ports->name, len) == 0) { 1727 if (port_name[len] == '\0') 1728 return ports->number; 1729 else if(isdigit(port_name[len])) { 1730 int port = ports->number + strtoul(&port_name[len], NULL, 0); 1731 if (port >= ports->number + ports->nr_ports) 1732 device_error(me, "Interrupt port %s out of range", 1733 port_name); 1734 return port; 1735 } 1736 } 1737 } 1738 else if (strcmp(port_name, ports->name) == 0) 1739 return ports->number; 1740 } 1741 ports++; 1742 } 1743 } 1744 } 1745 device_error(me, "Unreconized interrupt port %s", port_name); 1746 return 0; 1747} 1748 1749INLINE_DEVICE\ 1750(int) 1751device_interrupt_encode(device *me, 1752 int port_number, 1753 char *buf, 1754 int sizeof_buf, 1755 port_direction direction) 1756{ 1757 const device_interrupt_port_descriptor *ports = NULL; 1758 ports = me->callback->interrupt.ports; 1759 if (ports != NULL) { 1760 while (ports->name != NULL) { 1761 if (ports->direction == bidirect_port 1762 || ports->direction == direction) { 1763 if (ports->nr_ports > 0) { 1764 if (port_number >= ports->number 1765 && port_number < ports->number + ports->nr_ports) { 1766 strcpy(buf, ports->name); 1767 sprintf(buf + strlen(buf), "%d", port_number - ports->number); 1768 if (strlen(buf) >= sizeof_buf) 1769 error("device_interrupt_encode: buffer overflow"); 1770 return strlen(buf); 1771 } 1772 } 1773 else { 1774 if (ports->number == port_number) { 1775 if (strlen(ports->name) >= sizeof_buf) 1776 error("device_interrupt_encode: buffer overflow"); 1777 strcpy(buf, ports->name); 1778 return strlen(buf); 1779 } 1780 } 1781 } 1782 ports++; 1783 } 1784 } 1785 sprintf(buf, "%d", port_number); 1786 if (strlen(buf) >= sizeof_buf) 1787 error("device_interrupt_encode: buffer overflow"); 1788 return strlen(buf); 1789} 1790 1791 1792 1793/* IOCTL: */ 1794 1795EXTERN_DEVICE\ 1796(int) 1797device_ioctl(device *me, 1798 cpu *processor, 1799 unsigned_word cia, 1800 device_ioctl_request request, 1801 ...) 1802{ 1803 int status; 1804 va_list ap; 1805 va_start(ap, request); 1806 if (me->callback->ioctl == NULL) 1807 device_error(me, "no ioctl method"); 1808 status = me->callback->ioctl(me, processor, cia, request, ap); 1809 va_end(ap); 1810 return status; 1811} 1812 1813 1814 1815/* I/O */ 1816 1817EXTERN_DEVICE\ 1818(void) 1819device_error(device *me, 1820 const char *fmt, 1821 ...) 1822{ 1823 char message[1024]; 1824 va_list ap; 1825 /* format the message */ 1826 va_start(ap, fmt); 1827 vsprintf(message, fmt, ap); 1828 va_end(ap); 1829 /* sanity check */ 1830 if (strlen(message) >= sizeof(message)) 1831 error("device_error: buffer overflow"); 1832 if (me == NULL) 1833 error("device: %s", message); 1834 else if (me->path != NULL && me->path[0] != '\0') 1835 error("%s: %s", me->path, message); 1836 else if (me->name != NULL && me->name[0] != '\0') 1837 error("%s: %s", me->name, message); 1838 else 1839 error("device: %s", message); 1840 while(1); 1841} 1842 1843INLINE_DEVICE\ 1844(int) 1845device_trace(device *me) 1846{ 1847 return me->trace; 1848} 1849 1850 1851/* External representation */ 1852 1853INLINE_DEVICE\ 1854(device *) 1855external_to_device(device *tree_member, 1856 unsigned_cell phandle) 1857{ 1858 device *me = cap_internal(tree_member->phandles, phandle); 1859 return me; 1860} 1861 1862INLINE_DEVICE\ 1863(unsigned_cell) 1864device_to_external(device *me) 1865{ 1866 unsigned_cell phandle = cap_external(me->phandles, me); 1867 return phandle; 1868} 1869 1870INLINE_DEVICE\ 1871(device_instance *) 1872external_to_device_instance(device *tree_member, 1873 unsigned_cell ihandle) 1874{ 1875 device_instance *instance = cap_internal(tree_member->ihandles, ihandle); 1876 return instance; 1877} 1878 1879INLINE_DEVICE\ 1880(unsigned_cell) 1881device_instance_to_external(device_instance *instance) 1882{ 1883 unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance); 1884 return ihandle; 1885} 1886 1887 1888/* Map onto the event functions */ 1889 1890INLINE_DEVICE\ 1891(event_entry_tag) 1892device_event_queue_schedule(device *me, 1893 signed64 delta_time, 1894 device_event_handler *handler, 1895 void *data) 1896{ 1897 return event_queue_schedule(psim_event_queue(me->system), 1898 delta_time, 1899 handler, 1900 data); 1901} 1902 1903INLINE_DEVICE\ 1904(void) 1905device_event_queue_deschedule(device *me, 1906 event_entry_tag event_to_remove) 1907{ 1908 event_queue_deschedule(psim_event_queue(me->system), 1909 event_to_remove); 1910} 1911 1912INLINE_DEVICE\ 1913(signed64) 1914device_event_queue_time(device *me) 1915{ 1916 return event_queue_time(psim_event_queue(me->system)); 1917} 1918 1919 1920/* Initialization: */ 1921 1922 1923INLINE_DEVICE\ 1924(void) 1925device_clean(device *me, 1926 void *data) 1927{ 1928 psim *system; 1929 system = (psim*)data; 1930 TRACE(trace_device_init, ("device_clean - initializing %s", me->path)); 1931 clean_device_interrupt_edges(&me->interrupt_destinations); 1932 clean_device_instances(me); 1933 clean_device_properties(me); 1934} 1935 1936/* Device initialization: */ 1937 1938INLINE_DEVICE\ 1939(void) 1940device_init_address(device *me, 1941 void *data) 1942{ 1943 psim *system = (psim*)data; 1944 int nr_address_cells; 1945 int nr_size_cells; 1946 TRACE(trace_device_init, ("device_init_address - initializing %s", me->path)); 1947 1948 /* ensure the cap database is valid */ 1949 if (me->parent == NULL) { 1950 cap_init(me->ihandles); 1951 cap_init(me->phandles); 1952 } 1953 1954 /* some basics */ 1955 me->system = system; /* misc things not known until now */ 1956 me->trace = (device_find_property(me, "trace") 1957 ? device_find_integer_property(me, "trace") 1958 : 0); 1959 1960 /* Ensure that the first address found in the reg property matches 1961 anything that was specified as part of the devices name */ 1962 if (device_find_property(me, "reg") != NULL) { 1963 reg_property_spec unit; 1964 device_find_reg_array_property(me, "reg", 0, &unit); 1965 if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address)) 1966 != 0) 1967 device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path"); 1968 } 1969 1970 /* ensure that the devices #address/size-cells is consistent */ 1971 nr_address_cells = device_nr_address_cells(me); 1972 if (device_find_property(me, "#address-cells") != NULL 1973 && (nr_address_cells 1974 != device_find_integer_property(me, "#address-cells"))) 1975 device_error(me, "#address-cells property used before defined"); 1976 nr_size_cells = device_nr_size_cells(me); 1977 if (device_find_property(me, "#size-cells") != NULL 1978 && (nr_size_cells 1979 != device_find_integer_property(me, "#size-cells"))) 1980 device_error(me, "#size-cells property used before defined"); 1981 1982 /* now init it */ 1983 if (me->callback->init.address != NULL) 1984 me->callback->init.address(me); 1985} 1986 1987INLINE_DEVICE\ 1988(void) 1989device_init_data(device *me, 1990 void *data) 1991{ 1992 TRACE(trace_device_init, ("device_init_data - initializing %s", me->path)); 1993 if (me->callback->init.data != NULL) 1994 me->callback->init.data(me); 1995} 1996 1997#endif /* _DEVICE_C_ */ 1998