/*************************************************************************** devintrf.c Device interface functions. Copyright Nicola Salmoria and the MAME Team. Visit http://mamedev.org for licensing and usage restrictions. ***************************************************************************/ #include "driver.h" /*************************************************************************** CONSTANTS ***************************************************************************/ #define TEMP_STRING_POOL_ENTRIES 16 #define MAX_STRING_LENGTH 256 /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ static char temp_string_pool[TEMP_STRING_POOL_ENTRIES][MAX_STRING_LENGTH]; static int temp_string_pool_index; /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ static void device_list_stop(running_machine *machine); static void device_list_reset(running_machine *machine); /*************************************************************************** INLINE FUNCTIONS ***************************************************************************/ /*------------------------------------------------- get_temp_string_buffer - return a pointer to a temporary string buffer -------------------------------------------------*/ INLINE char *get_temp_string_buffer(void) { char *string = &temp_string_pool[temp_string_pool_index++ % TEMP_STRING_POOL_ENTRIES][0]; string[0] = 0; return string; } /*------------------------------------------------- device_matches_type - does a device match the provided type, taking wildcards into effect? -------------------------------------------------*/ INLINE int device_matches_type(const device_config *device, device_type type) { return (type == DEVICE_TYPE_WILDCARD) ? TRUE : (device->type == type); } /*************************************************************************** DEVICE CONFIGURATION ***************************************************************************/ /*------------------------------------------------- device_list_add - add a new device to the end of a device list -------------------------------------------------*/ device_config *device_list_add(device_config **listheadptr, device_type type, const char *tag) { device_config **devptr; device_config *device; UINT32 configlen; deviceinfo info; assert(listheadptr != NULL); assert(type != NULL); assert(tag != NULL); /* find the end of the list, and ensure no duplicates along the way */ for (devptr = listheadptr; *devptr != NULL; devptr = &(*devptr)->next) if (type == (*devptr)->type && strcmp(tag, (*devptr)->tag) == 0) fatalerror("Attempted to add duplicate device: type=%s tag=%s\n", devtype_name(type), tag); /* get the size of the inline config */ configlen = (UINT32)devtype_get_info_int(type, DEVINFO_INT_INLINE_CONFIG_BYTES); /* allocate a new device */ device = malloc_or_die(sizeof(*device) + strlen(tag) + configlen); /* populate all fields */ device->next = NULL; device->type = type; device->class = devtype_get_info_int(type, DEVINFO_INT_CLASS); device->static_config = NULL; device->inline_config = (configlen == 0) ? NULL : (device->tag + strlen(tag) + 1); device->token = NULL; device->machine = NULL; strcpy(device->tag, tag); /* reset the inline_config to 0 */ if (configlen > 0) memset(device->inline_config, 0, configlen); /* fetch function pointers to the core functions */ info.set_info = NULL; (*type)(NULL, DEVINFO_FCT_SET_INFO, &info); device->set_info = info.set_info; info.start = NULL; (*type)(NULL, DEVINFO_FCT_START, &info); device->start = info.start; info.stop = NULL; (*type)(NULL, DEVINFO_FCT_STOP, &info); device->stop = info.stop; info.reset = NULL; (*type)(NULL, DEVINFO_FCT_RESET, &info); device->reset = info.reset; /* link us to the end and return */ *devptr = device; return device; } /*------------------------------------------------- device_list_remove - remove a device from a device list -------------------------------------------------*/ void device_list_remove(device_config **listheadptr, device_type type, const char *tag) { device_config **devptr; device_config *device; assert(listheadptr != NULL); assert(type != NULL); assert(tag != NULL); /* find the device in the list */ for (devptr = listheadptr; *devptr != NULL; devptr = &(*devptr)->next) if (type == (*devptr)->type && strcmp(tag, (*devptr)->tag) == 0) break; if (*devptr == NULL) fatalerror("Attempted to remove non-existant device: type=%s tag=%s\n", devtype_name(type), tag); /* remove the device from the list */ device = *devptr; *devptr = device->next; /* free the device object */ free(device); } /*************************************************************************** TYPE-BASED DEVICE ACCESS ***************************************************************************/ /*------------------------------------------------- device_list_items - return the number of items of a given type; DEVICE_TYPE_WILDCARD is allowed -------------------------------------------------*/ int device_list_items(const device_config *listhead, device_type type) { const device_config *curdev; int count = 0; assert(type != NULL); /* locate all devices */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) count += device_matches_type(curdev, type); return count; } /*------------------------------------------------- device_list_first - return the first device in the list of a given type; DEVICE_TYPE_WILDCARD is allowed -------------------------------------------------*/ const device_config *device_list_first(const device_config *listhead, device_type type) { const device_config *curdev; /* scan forward starting with the list head */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (device_matches_type(curdev, type)) return curdev; return NULL; } /*------------------------------------------------- device_list_next - return the next device in the list of a given type; DEVICE_TYPE_WILDCARD is allowed -------------------------------------------------*/ const device_config *device_list_next(const device_config *prevdevice, device_type type) { const device_config *curdev; assert(prevdevice != NULL); /* scan forward starting with the item after the previous one */ for (curdev = prevdevice->next; curdev != NULL; curdev = curdev->next) if (device_matches_type(curdev, type)) return curdev; return NULL; } /*------------------------------------------------- device_list_find_by_tag - retrieve a device configuration based on a type and tag -------------------------------------------------*/ const device_config *device_list_find_by_tag(const device_config *listhead, device_type type, const char *tag) { const device_config *curdev; assert(tag != NULL); /* find the device in the list */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (device_matches_type(curdev, type) && strcmp(tag, curdev->tag) == 0) return curdev; /* fail */ return NULL; } /*------------------------------------------------- device_list_index - return the index of a device based on its type and tag; DEVICE_TYPE_WILDCARD is allowed -------------------------------------------------*/ int device_list_index(const device_config *listhead, device_type type, const char *tag) { const device_config *curdev; int index = 0; assert(type != NULL); assert(tag != NULL); /* locate all devices */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (device_matches_type(curdev, type)) { if (strcmp(tag, curdev->tag) == 0) return index; index++; } return -1; } /*------------------------------------------------- device_list_find_by_index - retrieve a device configuration based on a type and index -------------------------------------------------*/ const device_config *device_list_find_by_index(const device_config *listhead, device_type type, int index) { const device_config *curdev; assert(type != NULL); assert(index >= 0); /* find the device in the list */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (device_matches_type(curdev, type) && index-- == 0) return curdev; /* fail */ return NULL; } /*************************************************************************** CLASS-BASED DEVICE ACCESS ***************************************************************************/ /*------------------------------------------------- device_list_class_items - return the number of items of a given class -------------------------------------------------*/ int device_list_class_items(const device_config *listhead, device_class class) { const device_config *curdev; int count = 0; /* locate all devices */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) count += (curdev->class == class); return count; } /*------------------------------------------------- device_list_class_first - return the first device in the list of a given class -------------------------------------------------*/ const device_config *device_list_class_first(const device_config *listhead, device_class class) { const device_config *curdev; /* scan forward starting with the list head */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (curdev->class == class) return curdev; return NULL; } /*------------------------------------------------- device_list_class_next - return the next device in the list of a given class -------------------------------------------------*/ const device_config *device_list_class_next(const device_config *prevdevice, device_class class) { const device_config *curdev; assert(prevdevice != NULL); /* scan forward starting with the item after the previous one */ for (curdev = prevdevice->next; curdev != NULL; curdev = curdev->next) if (curdev->class == class) return curdev; return NULL; } /*------------------------------------------------- device_list_class_find_by_tag - retrieve a device configuration based on a class and tag -------------------------------------------------*/ const device_config *device_list_class_find_by_tag(const device_config *listhead, device_class class, const char *tag) { const device_config *curdev; assert(tag != NULL); /* find the device in the list */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (curdev->class == class && strcmp(tag, curdev->tag) == 0) return curdev; /* fail */ return NULL; } /*------------------------------------------------- device_list_class_index - return the index of a device based on its class and tag -------------------------------------------------*/ int device_list_class_index(const device_config *listhead, device_class class, const char *tag) { const device_config *curdev; int index = 0; assert(tag != NULL); /* locate all devices */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (curdev->class == class) { if (strcmp(tag, curdev->tag) == 0) return index; index++; } return -1; } /*------------------------------------------------- device_list_class_find_by_index - retrieve a device configuration based on a class and index -------------------------------------------------*/ const device_config *device_list_class_find_by_index(const device_config *listhead, device_class class, int index) { const device_config *curdev; assert(index >= 0); /* find the device in the list */ for (curdev = listhead; curdev != NULL; curdev = curdev->next) if (curdev->class == class && index-- == 0) return curdev; /* fail */ return NULL; } /*************************************************************************** LIVE DEVICE MANAGEMENT ***************************************************************************/ /*------------------------------------------------- device_list_start - start the configured list of devices for a machine -------------------------------------------------*/ void device_list_start(running_machine *machine) { device_config *device; assert(machine != NULL); /* add an exit callback for cleanup */ add_reset_callback(machine, device_list_reset); add_exit_callback(machine, device_list_stop); /* iterate over devices and start them */ for (device = (device_config *)machine->config->devicelist; device != NULL; device = device->next) { UINT32 tokenlen; assert(device->token == NULL); assert(device->type != NULL); assert(device->start != NULL); /* get the size of the token data */ tokenlen = (UINT32)devtype_get_info_int(device->type, DEVINFO_INT_TOKEN_BYTES); if (tokenlen == 0) fatalerror("Device %s specifies a 0 token length!\n", devtype_name(device->type)); /* allocate memory for the token */ device->token = malloc_or_die(tokenlen); memset(device->token, 0, tokenlen); /* call the start function */ device->machine = machine; (*device->start)(device); } } /*------------------------------------------------- device_list_stop - stop the configured list of devices for a machine -------------------------------------------------*/ static void device_list_stop(running_machine *machine) { device_config *device; assert(machine != NULL); /* iterate over devices and stop them */ for (device = (device_config *)machine->config->devicelist; device != NULL; device = device->next) { assert(device->token != NULL); assert(device->type != NULL); /* if we have a stop function, call it */ if (device->stop != NULL) (*device->stop)(device); /* free allocated memory for the token */ if (device->token != NULL) free(device->token); device->token = NULL; device->machine = NULL; } } /*------------------------------------------------- device_list_reset - reset the configured list of devices for a machine -------------------------------------------------*/ static void device_list_reset(running_machine *machine) { const device_config *device; assert(machine != NULL); /* iterate over devices and stop them */ for (device = (device_config *)machine->config->devicelist; device != NULL; device = device->next) device_reset(device); } /*------------------------------------------------- device_reset - reset a device based on an allocated device_config -------------------------------------------------*/ void device_reset(const device_config *device) { assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); /* if we have a reset function, call it */ if (device->reset != NULL) (*device->reset)(device); } void devtag_reset(running_machine *machine, device_type type, const char *tag) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_reset failed to find device: type=%s tag=%s\n", devtype_name(type), tag); device_reset(device); } /*************************************************************************** DEVICE INFORMATION GETTERS ***************************************************************************/ /*------------------------------------------------- devtag_get_token - return the token associated with an allocated device -------------------------------------------------*/ void *devtag_get_token(running_machine *machine, device_type type, const char *tag) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_get_token failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device->token; } /*------------------------------------------------- devtag_get_static_config - return a pointer to the static configuration for a device based on type and tag -------------------------------------------------*/ const void *devtag_get_static_config(running_machine *machine, device_type type, const char *tag) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_get_static_config failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device->static_config; } /*------------------------------------------------- devtag_get_inline_config - return a pointer to the inline configuration for a device based on type and tag -------------------------------------------------*/ const void *devtag_get_inline_config(running_machine *machine, device_type type, const char *tag) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_get_inline_config failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device->inline_config; } /*------------------------------------------------- device_get_info_int - return an integer state value from an allocated device -------------------------------------------------*/ INT64 device_get_info_int(const device_config *device, UINT32 state) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); /* retrieve the value */ info.i = 0; (*device->type)(device, state, &info); return info.i; } INT64 devtag_get_info_int(running_machine *machine, device_type type, const char *tag, UINT32 state) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_get_info_int failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device_get_info_int(device, state); } /*------------------------------------------------- device_get_info_ptr - return a pointer state value from an allocated device -------------------------------------------------*/ void *device_get_info_ptr(const device_config *device, UINT32 state) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_PTR_FIRST && state <= DEVINFO_PTR_LAST); /* retrieve the value */ info.p = NULL; (*device->type)(device, state, &info); return info.p; } void *devtag_get_info_ptr(running_machine *machine, device_type type, const char *tag, UINT32 state) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_get_info_ptr failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device_get_info_ptr(device, state); } /*------------------------------------------------- device_get_info_fct - return a function pointer state value from an allocated device -------------------------------------------------*/ genf *device_get_info_fct(const device_config *device, UINT32 state) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_FCT_FIRST && state <= DEVINFO_FCT_LAST); /* retrieve the value */ info.f = 0; (*device->type)(device, state, &info); return info.f; } genf *devtag_get_info_fct(running_machine *machine, device_type type, const char *tag, UINT32 state) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("device_get_info_fct failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device_get_info_fct(device, state); } /*------------------------------------------------- device_get_info_string - return a string value from an allocated device -------------------------------------------------*/ const char *device_get_info_string(const device_config *device, UINT32 state) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_STR_FIRST && state <= DEVINFO_STR_LAST); /* retrieve the value */ info.s = get_temp_string_buffer(); (*device->type)(device, state, &info); return info.s; } const char *devtag_get_info_string(running_machine *machine, device_type type, const char *tag, UINT32 state) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("device_get_info_string failed to find device: type=%s tag=%s\n", devtype_name(type), tag); return device_get_info_string(device, state); } /*************************************************************************** DEVICE TYPE INFORMATION SETTERS ***************************************************************************/ /*------------------------------------------------- devtype_get_info_int - return an integer value from a device type (does not need to be allocated) -------------------------------------------------*/ INT64 devtype_get_info_int(device_type type, UINT32 state) { deviceinfo info; assert(type != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); /* retrieve the value */ info.i = 0; (*type)(NULL, state, &info); return info.i; } /*------------------------------------------------- devtype_get_info_string - return a string value from a device type (does not need to be allocated) -------------------------------------------------*/ const char *devtype_get_info_string(device_type type, UINT32 state) { deviceinfo info; assert(type != NULL); assert(state >= DEVINFO_STR_FIRST && state <= DEVINFO_STR_LAST); /* retrieve the value */ info.s = get_temp_string_buffer(); (*type)(NULL, state, &info); return info.s; } /*************************************************************************** DEVICE INFORMATION SETTERS ***************************************************************************/ /*------------------------------------------------- device_set_info_int - set an integer state value for an allocated device -------------------------------------------------*/ void device_set_info_int(const device_config *device, UINT32 state, INT64 data) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); /* set the value */ info.i = data; (*device->set_info)(device, state, &info); } void devtag_set_info_int(running_machine *machine, device_type type, const char *tag, UINT32 state, INT64 data) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_set_info_int failed to find device: type=%s tag=%s\n", devtype_name(type), tag); device_set_info_int(device, state, data); } /*------------------------------------------------- device_set_info_ptr - set a pointer state value for an allocated device -------------------------------------------------*/ void device_set_info_ptr(const device_config *device, UINT32 state, void *data) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_PTR_FIRST && state <= DEVINFO_PTR_LAST); /* set the value */ info.p = data; (*device->set_info)(device, state, &info); } void devtag_set_info_ptr(running_machine *machine, device_type type, const char *tag, UINT32 state, void *data) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_set_info_ptr failed to find device: type=%s tag=%s\n", devtype_name(type), tag); device_set_info_ptr(device, state, data); } /*------------------------------------------------- device_set_info_fct - set a function pointer state value for an allocated device -------------------------------------------------*/ void device_set_info_fct(const device_config *device, UINT32 state, genf *data) { deviceinfo info; assert(device != NULL); assert(device->token != NULL); assert(device->type != NULL); assert(state >= DEVINFO_FCT_FIRST && state <= DEVINFO_FCT_LAST); /* set the value */ info.f = data; (*device->set_info)(device, state, &info); } void devtag_set_info_fct(running_machine *machine, device_type type, const char *tag, UINT32 state, genf *data) { const device_config *device; assert(machine != NULL); assert(type != NULL); assert(tag != NULL); assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST); device = device_list_find_by_tag(machine->config->devicelist, type, tag); if (device == NULL) fatalerror("devtag_set_info_fct failed to find device: type=%s tag=%s\n", devtype_name(type), tag); device_set_info_fct(device, state, data); }