carl9170 firmware: import 1.7.0
[carl9170fw.git] / tools / src / miniboot.c
1 /*
2  * Copyright 2010, Christian Lamparter <chunkeey@googlemail.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <error.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include "carlfw.h"
28
29 #include "compiler.h"
30
31 static void mini_help(void)
32 {
33         fprintf(stderr, "Usage:\n");
34         fprintf(stderr, "\tminiboot ACTION FW-FILE [MB-FILE]\n");
35
36         fprintf(stderr, "\nDescription:\n");
37         fprintf(stderr, "\tFirmware concatenation utility.\n");
38
39         fprintf(stderr, "\nParameteres:\n");
40         fprintf(stderr, "\t'ACTION'     = [a|d]\n");
41         fprintf(stderr, "\t | 'a'       = Add miniboot firmware.\n");
42         fprintf(stderr, "\t * 'd'       = remove miniboot firmware.\n");
43         fprintf(stderr, "\t'FW-FILE'    = destination for the package.\n");
44         fprintf(stderr, "\t'MB-FILE'    = extra firmware image.\n");
45 }
46
47 static int add_mini(struct carlfw *fw, const char *mini)
48 {
49         struct stat file_stat;
50         struct carl9170fw_otus_desc *otus_desc = NULL;
51         struct carl9170fw_usb_desc *usb_desc = NULL;
52         FILE *m = NULL;
53         char *buf = NULL;
54         size_t extra;
55         int err;
56
57         m = fopen(mini, "r");
58         if (m == NULL) {
59                 fprintf(stderr, "Failed to open file %s (%d).\n",
60                         mini, errno);
61                 err = -errno;
62                 goto fail;
63         }
64
65         err = fstat(fileno(m), &file_stat);
66         if (err) {
67                 fprintf(stderr, "Failed to query file infos from "
68                                 "\"%s\" (%d).\n", mini, errno);
69                 err = -errno;
70                 goto fail;
71         }
72         extra = file_stat.st_size;
73
74         otus_desc = carlfw_find_desc(fw, (uint8_t *) OTUS_MAGIC,
75                                      sizeof(*otus_desc),
76                                      CARL9170FW_OTUS_DESC_CUR_VER);
77         if (!otus_desc) {
78                 fprintf(stderr, "No OTUS descriptor found\n");
79                 goto fail;
80         }
81
82         usb_desc = carlfw_find_desc(fw, (uint8_t *) USB_MAGIC,
83                                     sizeof(*usb_desc),
84                                     CARL9170FW_USB_DESC_CUR_VER);
85         if (!usb_desc) {
86                 fprintf(stderr, "Firmware is not for USB devices.\n");
87                 goto fail;
88         }
89
90         if (carl9170fw_supports(usb_desc->usb_feature_set, CARL9170FW_USB_MINIBOOT)) {
91                 fprintf(stderr, "Firmware has already a miniboot image.\n");
92                 goto fail;
93         }
94
95         usb_desc->usb_feature_set |= cpu_to_le32(BIT(CARL9170FW_USB_MINIBOOT));
96         usb_desc->miniboot_size = cpu_to_le16(extra);
97
98         buf = carlfw_mod_headroom(fw, extra);
99         if (IS_ERR_OR_NULL(buf)) {
100                 fprintf(stderr, "Unable to add miniboot image.\n");
101                 goto fail;
102         }
103
104         err = fread(buf, extra, 1, m);
105         if (err != 1) {
106                 fprintf(stderr, "Unable to load miniboot.\n");
107                 goto fail;
108         }
109
110         carlfw_store(fw);
111         fclose(m);
112
113         return 0;
114
115 fail:
116         if (m)
117                 fclose(m);
118
119         return err;
120 }
121
122 static int del_mini(struct carlfw *fw)
123 {
124         struct carl9170fw_usb_desc *usb_desc = NULL;
125         void *buf;
126         int cut;
127
128         usb_desc = carlfw_find_desc(fw, (uint8_t *) USB_MAGIC,
129                                     sizeof(*usb_desc),
130                                     CARL9170FW_USB_DESC_CUR_VER);
131         if (!usb_desc) {
132                 fprintf(stderr, "Firmware is not for USB devices.\n");
133                 return -ENODATA;
134         }
135
136         if (!carl9170fw_supports(usb_desc->usb_feature_set, CARL9170FW_USB_MINIBOOT)) {
137                 fprintf(stderr, "Firmware has no miniboot image.\n");
138                 return -EINVAL;
139         }
140
141         cut = le16_to_cpu(usb_desc->miniboot_size);
142
143         buf = carlfw_mod_headroom(fw, -cut);
144         if (IS_ERR_OR_NULL(buf)) {
145                 fprintf(stderr, "Unable to remove miniboot.\n");
146                 return PTR_ERR(buf);
147         }
148
149         usb_desc->usb_feature_set &= cpu_to_le32(~BIT(CARL9170FW_USB_MINIBOOT));
150         usb_desc->miniboot_size = cpu_to_le16(0);
151
152         carlfw_store(fw);
153         return 0;
154 }
155
156 int main(int argc, char *args[])
157 {
158         struct carlfw *fw = NULL;
159         int err;
160
161         if (argc < 3 || argc > 4) {
162                 err = -EINVAL;
163                 goto err_param;
164         }
165
166         switch (args[1][0]) {
167         case 'a':
168                 if (argc != 4)
169                         goto err_param;
170
171                 fw = carlfw_load(args[2]);
172                 if (IS_ERR_OR_NULL(fw)) {
173                         err = PTR_ERR(fw);
174                         goto err_out;
175                 }
176
177                 err = add_mini(fw, args[3]);
178                 break;
179         case 'd':
180                 if (argc != 3)
181                         goto err_param;
182
183                 fw = carlfw_load(args[2]);
184                 if (IS_ERR_OR_NULL(fw)) {
185                         err = PTR_ERR(fw);
186                         goto err_out;
187                 }
188
189                 err = del_mini(fw);
190                 break;
191
192         default:
193                 goto err_param;
194                 break;
195         }
196
197         carlfw_release(fw);
198         return EXIT_SUCCESS;
199
200 err_out:
201         carlfw_release(fw);
202         fprintf(stderr, "miniboot action failed (%d).\n", err);
203         return EXIT_FAILURE;
204
205 err_param:
206         carlfw_release(fw);
207         mini_help();
208         return EXIT_FAILURE;
209 }