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
29static const char*
30getHaikuFirmwareName(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
46const struct firmware*
47firmware_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
57	haikuFirmwareName = getHaikuFirmwareName(fbsdFirmwareName,
58		fbsdFirmwareName);
59
60	firmwarePath = (char*)malloc(B_PATH_NAME_LENGTH);
61	if (firmwarePath == NULL)
62		goto cleanup;
63
64	if (find_directory(B_SYSTEM_DATA_DIRECTORY, -1, false,
65		firmwarePath, B_PATH_NAME_LENGTH) != B_OK)
66		goto cleanup;
67
68	strlcat(firmwarePath, "/firmware/", B_PATH_NAME_LENGTH);
69	strlcat(firmwarePath, gDriverName, B_PATH_NAME_LENGTH);
70	strlcat(firmwarePath, "/", B_PATH_NAME_LENGTH);
71	strlcat(firmwarePath, haikuFirmwareName, B_PATH_NAME_LENGTH);
72
73	fileDescriptor = open(firmwarePath, B_READ_ONLY);
74	if (fileDescriptor == -1)
75		goto cleanup;
76
77	firmwareFileSize = lseek(fileDescriptor, 0, SEEK_END);
78	if (firmwareFileSize == -1)
79		goto cleanup;
80
81	lseek(fileDescriptor, 0, SEEK_SET);
82
83	fbsdFirmwareNameCopy = strndup(fbsdFirmwareName,
84		MAX_FBSD_FIRMWARE_NAME_CHARS);
85	if (fbsdFirmwareNameCopy == NULL)
86		goto cleanup;
87
88	firmware = (struct firmware*)malloc(sizeof(struct firmware));
89	if (firmware == NULL)
90		goto cleanup;
91
92	firmware->data = malloc(firmwareFileSize);
93	if (firmware->data == NULL)
94		goto cleanup;
95
96	readCount = read(fileDescriptor, (void*)firmware->data, firmwareFileSize);
97	if (readCount == -1 || readCount < firmwareFileSize) {
98		free((void*)firmware->data);
99		goto cleanup;
100	}
101
102	firmware->datasize = firmwareFileSize;
103	firmware->name = fbsdFirmwareNameCopy;
104	firmware->version = __haiku_firmware_version;
105
106	close(fileDescriptor);
107	free(firmwarePath);
108	return firmware;
109
110cleanup:
111	if (firmware)
112		free(firmware);
113	if (fbsdFirmwareNameCopy)
114		free(fbsdFirmwareNameCopy);
115	if (firmwarePath)
116		free(firmwarePath);
117	if (fileDescriptor >= 0)
118		close(fileDescriptor);
119	return NULL;
120}
121
122
123void
124firmware_put(const struct firmware* firmware, int flags)
125{
126	if (firmware == NULL)
127		return;
128
129	if (firmware->data)
130		free((void*)firmware->data);
131	if (firmware->name)
132		free((void*)firmware->name);
133	free((void*)firmware);
134}
135