1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/types.h>
30#include <sys/endian.h>
31#include <sys/stat.h>
32
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include "iwmbt_fw.h"
42#include "iwmbt_dbg.h"
43
44int
45iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname)
46{
47	int fd;
48	struct stat sb;
49	unsigned char *buf;
50	ssize_t r;
51
52	fd = open(fwname, O_RDONLY);
53	if (fd < 0) {
54		warn("%s: open: %s", __func__, fwname);
55		return (0);
56	}
57
58	if (fstat(fd, &sb) != 0) {
59		warn("%s: stat: %s", __func__, fwname);
60		close(fd);
61		return (0);
62	}
63
64	buf = calloc(1, sb.st_size);
65	if (buf == NULL) {
66		warn("%s: calloc", __func__);
67		close(fd);
68		return (0);
69	}
70
71	/* XXX handle partial reads */
72	r = read(fd, buf, sb.st_size);
73	if (r < 0) {
74		warn("%s: read", __func__);
75		free(buf);
76		close(fd);
77		return (0);
78	}
79
80	if (r != sb.st_size) {
81		iwmbt_err("read len %d != file size %d",
82		    (int) r,
83		    (int) sb.st_size);
84		free(buf);
85		close(fd);
86		return (0);
87	}
88
89	/* We have everything, so! */
90
91	memset(fw, 0, sizeof(*fw));
92
93	fw->fwname = strdup(fwname);
94	fw->len = sb.st_size;
95	fw->buf = buf;
96
97	close(fd);
98	return (1);
99}
100
101void
102iwmbt_fw_free(struct iwmbt_firmware *fw)
103{
104	if (fw->fwname)
105		free(fw->fwname);
106	if (fw->buf)
107		free(fw->buf);
108	memset(fw, 0, sizeof(*fw));
109}
110
111char *
112iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
113    const char *prefix, const char *suffix)
114{
115	struct stat sb;
116	char *fwname;
117
118	switch (ver->hw_variant) {
119	case 0x07:	/* 7260 */
120	case 0x08:	/* 7265 */
121		asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s",
122		    prefix,
123		    le16toh(ver->hw_platform),
124		    le16toh(ver->hw_variant),
125		    le16toh(ver->hw_revision),
126		    le16toh(ver->fw_variant),
127		    le16toh(ver->fw_revision),
128		    le16toh(ver->fw_build_num),
129		    le16toh(ver->fw_build_ww),
130		    le16toh(ver->fw_build_yy),
131		    suffix);
132		/*
133		 * Fallback to the default firmware patch if
134		 * the correct firmware patch file is not found.
135		 */
136		if (stat(fwname, &sb) != 0 && errno == ENOENT) {
137			free(fwname);
138			asprintf(&fwname, "%s/ibt-hw-%x.%x.%s",
139			    prefix,
140			    le16toh(ver->hw_platform),
141			    le16toh(ver->hw_variant),
142			    suffix);
143		}
144		break;
145
146	case 0x0b:	/* 8260 */
147	case 0x0c:	/* 8265 */
148		asprintf(&fwname, "%s/ibt-%u-%u.%s",
149		    prefix,
150		    le16toh(ver->hw_variant),
151		    le16toh(params->dev_revid),
152		    suffix);
153		break;
154
155	case 0x11:	/* 9560 */
156	case 0x12:	/* 9260 */
157	case 0x13:
158	case 0x14:	/* 22161 */
159		asprintf(&fwname, "%s/ibt-%u-%u-%u.%s",
160		    prefix,
161		    le16toh(ver->hw_variant),
162		    le16toh(ver->hw_revision),
163		    le16toh(ver->fw_revision),
164		    suffix);
165		break;
166
167	default:
168		fwname = NULL;
169	}
170
171	return (fwname);
172}
173