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*
getHaikuFirmwareName(const char * fbsdFirmwareName,const char * unknownFirmwareName)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*
firmware_get(const char * fbsdFirmwareName)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
firmware_put(const struct firmware * firmware,int flags)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