carl9170 firmware: add get_random_u16 helper
[carl9170fw.git] / tools / src / miniboot.c
1 /*
2  * Copyright 2010-2011 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         FILE *m = NULL;
52         char *buf = NULL;
53         size_t extra;
54         int err;
55
56         m = fopen(mini, "r");
57         if (m == NULL) {
58                 fprintf(stderr, "Failed to open file %s (%d).\n",
59                         mini, errno);
60                 err = -errno;
61                 goto fail;
62         }
63
64         err = fstat(fileno(m), &file_stat);
65         if (err) {
66                 fprintf(stderr, "Failed to query file infos from "
67                                 "\"%s\" (%d).\n", mini, errno);
68                 err = -errno;
69                 goto fail;
70         }
71         extra = file_stat.st_size;
72
73         otus_desc = carlfw_find_desc(fw, (uint8_t *) OTUS_MAGIC,
74                                      sizeof(*otus_desc),
75                                      CARL9170FW_OTUS_DESC_CUR_VER);
76         if (!otus_desc) {
77                 fprintf(stderr, "No OTUS descriptor found\n");
78                 goto fail;
79         }
80
81         if (carl9170fw_supports(otus_desc->feature_set, CARL9170FW_MINIBOOT)) {
82                 fprintf(stderr, "Firmware has already a miniboot image.\n");
83                 goto fail;
84         }
85
86         otus_desc->feature_set |= cpu_to_le32(BIT(CARL9170FW_MINIBOOT));
87         otus_desc->miniboot_size = cpu_to_le16(extra);
88
89         buf = carlfw_mod_headroom(fw, extra);
90         if (IS_ERR_OR_NULL(buf)) {
91                 fprintf(stderr, "Unable to add miniboot image.\n");
92                 goto fail;
93         }
94
95         err = fread(buf, extra, 1, m);
96         if (err != 1) {
97                 fprintf(stderr, "Unable to load miniboot.\n");
98                 goto fail;
99         }
100
101         carlfw_store(fw);
102         fclose(m);
103
104         return 0;
105
106 fail:
107         if (m)
108                 fclose(m);
109
110         return err;
111 }
112
113 static int del_mini(struct carlfw *fw)
114 {
115         struct carl9170fw_otus_desc *otus_desc = NULL;
116         void *buf;
117         int cut;
118
119         otus_desc = carlfw_find_desc(fw, (uint8_t *) OTUS_MAGIC,
120                                      sizeof(*otus_desc),
121                                      CARL9170FW_OTUS_DESC_CUR_VER);
122         if (!otus_desc) {
123                 fprintf(stderr, "Firmware is not for USB devices.\n");
124                 return -ENODATA;
125         }
126
127         if (!carl9170fw_supports(otus_desc->feature_set, CARL9170FW_MINIBOOT)) {
128                 fprintf(stderr, "Firmware has no miniboot image.\n");
129                 return -EINVAL;
130         }
131
132         cut = le16_to_cpu(otus_desc->miniboot_size);
133
134         buf = carlfw_mod_headroom(fw, -cut);
135         if (IS_ERR_OR_NULL(buf)) {
136                 fprintf(stderr, "Unable to remove miniboot.\n");
137                 return PTR_ERR(buf);
138         }
139
140         otus_desc->feature_set &= cpu_to_le32(~BIT(CARL9170FW_MINIBOOT));
141         otus_desc->miniboot_size = cpu_to_le16(0);
142
143         carlfw_store(fw);
144         return 0;
145 }
146
147 int main(int argc, char *args[])
148 {
149         struct carlfw *fw = NULL;
150         int err;
151
152         if (argc < 3 || argc > 4) {
153                 err = -EINVAL;
154                 goto err_param;
155         }
156
157         switch (args[1][0]) {
158         case 'a':
159                 if (argc != 4)
160                         goto err_param;
161
162                 fw = carlfw_load(args[2]);
163                 if (IS_ERR_OR_NULL(fw)) {
164                         err = PTR_ERR(fw);
165                         goto err_out;
166                 }
167
168                 err = add_mini(fw, args[3]);
169                 break;
170         case 'd':
171                 if (argc != 3)
172                         goto err_param;
173
174                 fw = carlfw_load(args[2]);
175                 if (IS_ERR_OR_NULL(fw)) {
176                         err = PTR_ERR(fw);
177                         goto err_out;
178                 }
179
180                 err = del_mini(fw);
181                 break;
182
183         default:
184                 goto err_param;
185                 break;
186         }
187
188         carlfw_release(fw);
189         return EXIT_SUCCESS;
190
191 err_out:
192         carlfw_release(fw);
193         fprintf(stderr, "miniboot action failed (%d).\n", err);
194         return EXIT_FAILURE;
195
196 err_param:
197         carlfw_release(fw);
198         mini_help();
199         return EXIT_FAILURE;
200 }