1 /* 2 * Copyright 2009-2010, Colin Günther, coling@gmx.de. 3 * All Rights Reserved. Distributed under the terms of the MIT License. 4 * 5 */ 6 7 8 #include <posix/sys/mman.h> 9 10 #include <compat/sys/param.h> 11 #include <compat/sys/firmware.h> 12 #include <compat/sys/haiku-module.h> 13 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <FindDirectory.h> 18 #include <StorageDefs.h> 19 #include <SupportDefs.h> 20 21 #include <device.h> 22 23 24 #define MAX_FBSD_FIRMWARE_NAME_CHARS 64 25 // For strndup, beeing cautious in kernel code is a good thing. 26 // NB: This constant doesn't exist in FreeBSD. 27 28 29 static const char* 30 getHaikuFirmwareName(const char* fbsdFirmwareName, 31 const char* unknownFirmwareName) 32 { 33 int i; 34 35 if (__haiku_firmware_name_map == NULL) 36 return unknownFirmwareName; 37 38 for (i = 0; i < __haiku_firmware_parts_count; i++) { 39 if (strcmp(__haiku_firmware_name_map[i][0], fbsdFirmwareName) == 0) 40 return __haiku_firmware_name_map[i][1]; 41 } 42 return unknownFirmwareName; 43 } 44 45 46 const struct firmware* 47 firmware_get(const char* fbsdFirmwareName) 48 { 49 char* fbsdFirmwareNameCopy = NULL; 50 int fileDescriptor = -1; 51 struct firmware* firmware = NULL; 52 int32 firmwareFileSize; 53 char* firmwarePath = NULL; 54 const char* haikuFirmwareName = NULL; 55 ssize_t readCount = 0; 56 directory_which checkDirs[] = { B_SYSTEM_NONPACKAGED_DATA_DIRECTORY, 57 B_SYSTEM_DATA_DIRECTORY }; 58 size_t numCheckDirs 59 = sizeof(checkDirs) / sizeof(checkDirs[0]); 60 size_t i = 0; 61 62 haikuFirmwareName = getHaikuFirmwareName(fbsdFirmwareName, 63 fbsdFirmwareName); 64 65 firmwarePath = (char*)malloc(B_PATH_NAME_LENGTH); 66 if (firmwarePath == NULL) 67 goto cleanup; 68 69 70 for (; i < numCheckDirs; i++) { 71 if (find_directory(checkDirs[i], -1, false, firmwarePath, 72 B_PATH_NAME_LENGTH) != B_OK) { 73 continue; 74 } 75 76 strlcat(firmwarePath, "/firmware/", B_PATH_NAME_LENGTH); 77 strlcat(firmwarePath, gDriverName, B_PATH_NAME_LENGTH); 78 strlcat(firmwarePath, "/", B_PATH_NAME_LENGTH); 79 strlcat(firmwarePath, haikuFirmwareName, B_PATH_NAME_LENGTH); 80 81 fileDescriptor = open(firmwarePath, B_READ_ONLY); 82 if (fileDescriptor >= 0) 83 break; 84 } 85 86 if (fileDescriptor < 0) 87 goto cleanup; 88 89 firmwareFileSize = lseek(fileDescriptor, 0, SEEK_END); 90 if (firmwareFileSize == -1) 91 goto cleanup; 92 93 lseek(fileDescriptor, 0, SEEK_SET); 94 95 fbsdFirmwareNameCopy = strndup(fbsdFirmwareName, 96 MAX_FBSD_FIRMWARE_NAME_CHARS); 97 if (fbsdFirmwareNameCopy == NULL) 98 goto cleanup; 99 100 firmware = (struct firmware*)malloc(sizeof(struct firmware)); 101 if (firmware == NULL) 102 goto cleanup; 103 104 firmware->data = malloc(firmwareFileSize); 105 if (firmware->data == NULL) 106 goto cleanup; 107 108 readCount = read(fileDescriptor, (void*)firmware->data, firmwareFileSize); 109 if (readCount == -1 || readCount < firmwareFileSize) { 110 free((void*)firmware->data); 111 goto cleanup; 112 } 113 114 firmware->datasize = firmwareFileSize; 115 firmware->name = fbsdFirmwareNameCopy; 116 firmware->version = __haiku_firmware_version; 117 118 close(fileDescriptor); 119 free(firmwarePath); 120 return firmware; 121 122 cleanup: 123 if (firmware) 124 free(firmware); 125 if (fbsdFirmwareNameCopy) 126 free(fbsdFirmwareNameCopy); 127 if (firmwarePath) 128 free(firmwarePath); 129 if (fileDescriptor >= 0) 130 close(fileDescriptor); 131 return NULL; 132 } 133 134 135 void 136 firmware_put(const struct firmware* firmware, int flags) 137 { 138 if (firmware == NULL) 139 return; 140 141 if (firmware->data) 142 free((void*)firmware->data); 143 if (firmware->name) 144 free((void*)firmware->name); 145 free((void*)firmware); 146 } 147