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