| /* |
| * BRLTTY - A background process providing access to the console screen (when in |
| * text mode) for a blind person using a refreshable braille display. |
| * |
| * Copyright (C) 1995-2023 by The BRLTTY Developers. |
| * |
| * BRLTTY comes with ABSOLUTELY NO WARRANTY. |
| * |
| * This is free software, placed under the terms of the |
| * GNU Lesser General Public License, as published by the Free Software |
| * Foundation; either version 2.1 of the License, or (at your option) any |
| * later version. Please see the file LICENSE-LGPL for details. |
| * |
| * Web Page: http://brltty.app/ |
| * |
| * This software is maintained by Dave Mielke <dave@mielke.cc>. |
| */ |
| |
| #include "prologue.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "log.h" |
| #include "strfmt.h" |
| #include "file.h" |
| #include "dynld.h" |
| #include "drivers.h" |
| |
| int |
| isDriverAvailable (const char *code, const char *codes) { |
| int length = strlen(code); |
| const char *string = codes; |
| |
| while ((string = strstr(string, code))) { |
| if (((string == codes) || (string[-1] == ' ')) && |
| (!string[length] || (string[length] == ' '))) { |
| return 1; |
| } |
| |
| string += length; |
| } |
| |
| return 0; |
| } |
| |
| int |
| isDriverIncluded (const char *code, const DriverEntry *table) { |
| while (table->address) { |
| if (strcmp(code, table->definition->code) == 0) return 1; |
| ++table; |
| } |
| return 0; |
| } |
| |
| int |
| haveDriver (const char *code, const char *codes, const DriverEntry *table) { |
| return (table && table->address)? isDriverIncluded(code, table): |
| isDriverAvailable(code, codes); |
| } |
| |
| const char * |
| getDefaultDriver (const DriverEntry *table) { |
| return (table && table[0].address && !table[1].address)? table[0].definition->code: NULL; |
| } |
| |
| static int |
| isDriverCode (const char *code, const DriverDefinition *definition) { |
| if (strcmp(code, definition->code) == 0) return 1; |
| return 0; |
| } |
| |
| const void * |
| loadDriver ( |
| const char *driverCode, void **driverObject, |
| const char *driverDirectory, const DriverEntry *driverTable, |
| const char *typeName, char typeLetter, const char *symbolPrefix, |
| const void *nullAddress, const DriverDefinition *nullDefinition |
| ) { |
| const void *driverAddress = NULL; |
| *driverObject = NULL; |
| |
| if (!driverCode || !*driverCode) { |
| if (driverTable) |
| if (driverTable->address) |
| return driverTable->address; |
| return nullAddress; |
| } |
| |
| if (isDriverCode(driverCode, nullDefinition)) return nullAddress; |
| |
| if (driverTable) { |
| const DriverEntry *driverEntry = driverTable; |
| while (driverEntry->address) { |
| if (isDriverCode(driverCode, driverEntry->definition)) return driverEntry->address; |
| ++driverEntry; |
| } |
| } |
| |
| #ifdef ENABLE_SHARED_OBJECTS |
| { |
| char *libraryPath; |
| const int libraryNameLength = strlen(MODULE_NAME) + strlen(driverCode) + strlen(MODULE_EXTENSION) + 3; |
| char libraryName[libraryNameLength]; |
| snprintf(libraryName, libraryNameLength, "%s%c%s.%s", |
| MODULE_NAME, typeLetter, driverCode, MODULE_EXTENSION); |
| |
| if ((libraryPath = makePath(driverDirectory, libraryName))) { |
| void *libraryHandle = loadSharedObject(libraryPath); |
| |
| if (libraryHandle) { |
| const int driverSymbolLength = strlen(symbolPrefix) + 8 + strlen(driverCode) + 1; |
| char driverSymbol[driverSymbolLength]; |
| snprintf(driverSymbol, driverSymbolLength, "%s_driver_%s", |
| symbolPrefix, driverCode); |
| |
| if (findSharedSymbol(libraryHandle, driverSymbol, &driverAddress)) { |
| *driverObject = libraryHandle; |
| |
| { |
| const void *versionAddress = NULL; |
| const int versionSymbolLength = strlen(symbolPrefix) + 9 + strlen(driverCode) + 1; |
| char versionSymbol[versionSymbolLength]; |
| snprintf(versionSymbol, versionSymbolLength, "%s_version_%s", |
| symbolPrefix, driverCode); |
| |
| if (findSharedSymbol(libraryHandle, versionSymbol, &versionAddress)) { |
| const char *actualVersion = versionAddress; |
| static const char *expectedVersion = DRIVER_VERSION_STRING; |
| |
| if (strcmp(actualVersion, expectedVersion) != 0) { |
| logMessage(LOG_WARNING, |
| "%s driver version mismatch: %s: Expected:%s Actual%s", |
| typeName, driverCode, |
| expectedVersion, actualVersion |
| ); |
| } |
| } else { |
| logMessage(LOG_WARNING, |
| "cannot find %s driver version symbol: %s: %s", |
| typeName, driverCode, versionSymbol |
| ); |
| } |
| } |
| } else { |
| logMessage(LOG_ERR, |
| "cannot find %s driver symbol: %s", |
| typeName, driverSymbol |
| ); |
| |
| unloadSharedObject(libraryHandle); |
| driverAddress = NULL; |
| } |
| } else { |
| logMessage(LOG_ERR, |
| "cannot load %s driver: %s", |
| typeName, libraryPath |
| ); |
| } |
| |
| free(libraryPath); |
| } |
| } |
| #endif /* ENABLE_SHARED_OBJECTS */ |
| |
| return driverAddress; |
| } |
| |
| void |
| identifyDriver ( |
| const char *type, |
| const DriverDefinition *definition, |
| int full |
| ) { |
| { |
| char buffer[0X100]; |
| STR_BEGIN(buffer, sizeof(buffer)); |
| |
| STR_PRINTF( |
| "%s Driver: %s [%s]", |
| type, definition->code, definition->name |
| ); |
| |
| if (definition->version && *definition->version) { |
| STR_PRINTF(" Version:%s", definition->version); |
| } |
| |
| if (full) { |
| STR_PRINTF(" (compiled on %s at %s)", definition->date, definition->time); |
| } |
| |
| STR_END; |
| logMessage(LOG_NOTICE, "%s", buffer); |
| } |
| |
| if (full) { |
| if (definition->developers && *definition->developers) { |
| logMessage(LOG_INFO, " Developed by %s", definition->developers); |
| } |
| } |
| } |