Commit 5644369450635fa5c2967bee55b1ac41f6e988d0
Exists in
master
and in
53 other branches
Merge branch 'agust@denx.de' of git://git.denx.de/u-boot-staging
Showing 10 changed files Inline Diff
board/ait/cam_enc_4xx/cam_enc_4xx.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2009 Texas Instruments Incorporated | 2 | * Copyright (C) 2009 Texas Instruments Incorporated |
3 | * | 3 | * |
4 | * Copyright (C) 2011 | 4 | * Copyright (C) 2011 |
5 | * Heiko Schocher, DENX Software Engineering, hs@denx.de. | 5 | * Heiko Schocher, DENX Software Engineering, hs@denx.de. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <common.h> | 22 | #include <common.h> |
23 | #include <errno.h> | 23 | #include <errno.h> |
24 | #include <hush.h> | 24 | #include <hush.h> |
25 | #include <linux/mtd/nand.h> | 25 | #include <linux/mtd/nand.h> |
26 | #include <nand.h> | 26 | #include <nand.h> |
27 | #include <miiphy.h> | 27 | #include <miiphy.h> |
28 | #include <netdev.h> | 28 | #include <netdev.h> |
29 | #include <asm/io.h> | 29 | #include <asm/io.h> |
30 | #include <asm/arch/hardware.h> | 30 | #include <asm/arch/hardware.h> |
31 | #include <asm/arch/nand_defs.h> | 31 | #include <asm/arch/nand_defs.h> |
32 | #include <asm/arch/davinci_misc.h> | 32 | #include <asm/arch/davinci_misc.h> |
33 | #ifdef CONFIG_DAVINCI_MMC | 33 | #ifdef CONFIG_DAVINCI_MMC |
34 | #include <mmc.h> | 34 | #include <mmc.h> |
35 | #include <asm/arch/sdmmc_defs.h> | 35 | #include <asm/arch/sdmmc_defs.h> |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | DECLARE_GLOBAL_DATA_PTR; | 38 | DECLARE_GLOBAL_DATA_PTR; |
39 | 39 | ||
40 | #ifndef CONFIG_SPL_BUILD | 40 | #ifndef CONFIG_SPL_BUILD |
41 | static struct davinci_timer *timer = | 41 | static struct davinci_timer *timer = |
42 | (struct davinci_timer *)DAVINCI_TIMER3_BASE; | 42 | (struct davinci_timer *)DAVINCI_TIMER3_BASE; |
43 | 43 | ||
44 | static unsigned long get_timer_val(void) | 44 | static unsigned long get_timer_val(void) |
45 | { | 45 | { |
46 | unsigned long now = readl(&timer->tim34); | 46 | unsigned long now = readl(&timer->tim34); |
47 | 47 | ||
48 | return now; | 48 | return now; |
49 | } | 49 | } |
50 | 50 | ||
51 | static int timer_running(void) | 51 | static int timer_running(void) |
52 | { | 52 | { |
53 | return readl(&timer->tcr) & | 53 | return readl(&timer->tcr) & |
54 | (DV_TIMER_TCR_ENAMODE_MASK << DV_TIMER_TCR_ENAMODE34_SHIFT); | 54 | (DV_TIMER_TCR_ENAMODE_MASK << DV_TIMER_TCR_ENAMODE34_SHIFT); |
55 | } | 55 | } |
56 | 56 | ||
57 | static void stop_timer(void) | 57 | static void stop_timer(void) |
58 | { | 58 | { |
59 | writel(0x0, &timer->tcr); | 59 | writel(0x0, &timer->tcr); |
60 | return; | 60 | return; |
61 | } | 61 | } |
62 | 62 | ||
63 | int checkboard(void) | 63 | int checkboard(void) |
64 | { | 64 | { |
65 | printf("Board: AIT CAM ENC 4XX\n"); | 65 | printf("Board: AIT CAM ENC 4XX\n"); |
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | int board_init(void) | 69 | int board_init(void) |
70 | { | 70 | { |
71 | gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; | 71 | gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; |
72 | 72 | ||
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | 75 | ||
76 | #ifdef CONFIG_DRIVER_TI_EMAC | 76 | #ifdef CONFIG_DRIVER_TI_EMAC |
77 | static int cam_enc_4xx_check_network(void) | 77 | static int cam_enc_4xx_check_network(void) |
78 | { | 78 | { |
79 | char *s; | 79 | char *s; |
80 | 80 | ||
81 | s = getenv("ethaddr"); | 81 | s = getenv("ethaddr"); |
82 | if (!s) | 82 | if (!s) |
83 | return -EINVAL; | 83 | return -EINVAL; |
84 | 84 | ||
85 | if (!is_valid_ether_addr((const u8 *)s)) | 85 | if (!is_valid_ether_addr((const u8 *)s)) |
86 | return -EINVAL; | 86 | return -EINVAL; |
87 | 87 | ||
88 | s = getenv("ipaddr"); | 88 | s = getenv("ipaddr"); |
89 | if (!s) | 89 | if (!s) |
90 | return -EINVAL; | 90 | return -EINVAL; |
91 | 91 | ||
92 | s = getenv("netmask"); | 92 | s = getenv("netmask"); |
93 | if (!s) | 93 | if (!s) |
94 | return -EINVAL; | 94 | return -EINVAL; |
95 | 95 | ||
96 | s = getenv("serverip"); | 96 | s = getenv("serverip"); |
97 | if (!s) | 97 | if (!s) |
98 | return -EINVAL; | 98 | return -EINVAL; |
99 | 99 | ||
100 | s = getenv("gatewayip"); | 100 | s = getenv("gatewayip"); |
101 | if (!s) | 101 | if (!s) |
102 | return -EINVAL; | 102 | return -EINVAL; |
103 | 103 | ||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | int board_eth_init(bd_t *bis) | 106 | int board_eth_init(bd_t *bis) |
107 | { | 107 | { |
108 | int ret; | 108 | int ret; |
109 | 109 | ||
110 | ret = cam_enc_4xx_check_network(); | 110 | ret = cam_enc_4xx_check_network(); |
111 | if (ret) | 111 | if (ret) |
112 | return ret; | 112 | return ret; |
113 | 113 | ||
114 | davinci_emac_initialize(); | 114 | davinci_emac_initialize(); |
115 | 115 | ||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | #endif | 118 | #endif |
119 | 119 | ||
120 | #ifdef CONFIG_NAND_DAVINCI | 120 | #ifdef CONFIG_NAND_DAVINCI |
121 | static int | 121 | static int |
122 | davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 122 | davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
123 | uint8_t *buf, int page) | 123 | uint8_t *buf, int page) |
124 | { | 124 | { |
125 | struct nand_chip *this = mtd->priv; | 125 | struct nand_chip *this = mtd->priv; |
126 | int i, eccsize = chip->ecc.size; | 126 | int i, eccsize = chip->ecc.size; |
127 | int eccbytes = chip->ecc.bytes; | 127 | int eccbytes = chip->ecc.bytes; |
128 | int eccsteps = chip->ecc.steps; | 128 | int eccsteps = chip->ecc.steps; |
129 | uint8_t *p = buf; | 129 | uint8_t *p = buf; |
130 | uint8_t *oob = chip->oob_poi; | 130 | uint8_t *oob = chip->oob_poi; |
131 | 131 | ||
132 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); | 132 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
133 | 133 | ||
134 | chip->read_buf(mtd, oob, mtd->oobsize); | 134 | chip->read_buf(mtd, oob, mtd->oobsize); |
135 | 135 | ||
136 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page & this->pagemask); | 136 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page & this->pagemask); |
137 | 137 | ||
138 | 138 | ||
139 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | 139 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
140 | int stat; | 140 | int stat; |
141 | 141 | ||
142 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | 142 | chip->ecc.hwctl(mtd, NAND_ECC_READ); |
143 | chip->read_buf(mtd, p, eccsize); | 143 | chip->read_buf(mtd, p, eccsize); |
144 | chip->ecc.hwctl(mtd, NAND_ECC_READSYN); | 144 | chip->ecc.hwctl(mtd, NAND_ECC_READSYN); |
145 | 145 | ||
146 | if (chip->ecc.prepad) | 146 | if (chip->ecc.prepad) |
147 | oob += chip->ecc.prepad; | 147 | oob += chip->ecc.prepad; |
148 | 148 | ||
149 | stat = chip->ecc.correct(mtd, p, oob, NULL); | 149 | stat = chip->ecc.correct(mtd, p, oob, NULL); |
150 | 150 | ||
151 | if (stat == -1) | 151 | if (stat == -1) |
152 | mtd->ecc_stats.failed++; | 152 | mtd->ecc_stats.failed++; |
153 | else | 153 | else |
154 | mtd->ecc_stats.corrected += stat; | 154 | mtd->ecc_stats.corrected += stat; |
155 | 155 | ||
156 | oob += eccbytes; | 156 | oob += eccbytes; |
157 | 157 | ||
158 | if (chip->ecc.postpad) | 158 | if (chip->ecc.postpad) |
159 | oob += chip->ecc.postpad; | 159 | oob += chip->ecc.postpad; |
160 | } | 160 | } |
161 | 161 | ||
162 | /* Calculate remaining oob bytes */ | 162 | /* Calculate remaining oob bytes */ |
163 | i = mtd->oobsize - (oob - chip->oob_poi); | 163 | i = mtd->oobsize - (oob - chip->oob_poi); |
164 | if (i) | 164 | if (i) |
165 | chip->read_buf(mtd, oob, i); | 165 | chip->read_buf(mtd, oob, i); |
166 | 166 | ||
167 | return 0; | 167 | return 0; |
168 | } | 168 | } |
169 | 169 | ||
170 | static void davinci_std_write_page_syndrome(struct mtd_info *mtd, | 170 | static void davinci_std_write_page_syndrome(struct mtd_info *mtd, |
171 | struct nand_chip *chip, const uint8_t *buf) | 171 | struct nand_chip *chip, const uint8_t *buf) |
172 | { | 172 | { |
173 | unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE]; | 173 | unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE]; |
174 | struct nand_chip *this = mtd->priv; | 174 | struct nand_chip *this = mtd->priv; |
175 | int i, eccsize = chip->ecc.size; | 175 | int i, eccsize = chip->ecc.size; |
176 | int eccbytes = chip->ecc.bytes; | 176 | int eccbytes = chip->ecc.bytes; |
177 | int eccsteps = chip->ecc.steps; | 177 | int eccsteps = chip->ecc.steps; |
178 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | 178 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; |
179 | int offset = 0; | 179 | int offset = 0; |
180 | const uint8_t *p = buf; | 180 | const uint8_t *p = buf; |
181 | uint8_t *oob = chip->oob_poi; | 181 | uint8_t *oob = chip->oob_poi; |
182 | 182 | ||
183 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | 183 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
184 | chip->ecc.hwctl(mtd, NAND_ECC_WRITE); | 184 | chip->ecc.hwctl(mtd, NAND_ECC_WRITE); |
185 | chip->write_buf(mtd, p, eccsize); | 185 | chip->write_buf(mtd, p, eccsize); |
186 | 186 | ||
187 | /* Calculate ECC without prepad */ | 187 | /* Calculate ECC without prepad */ |
188 | chip->ecc.calculate(mtd, p, oob + chip->ecc.prepad); | 188 | chip->ecc.calculate(mtd, p, oob + chip->ecc.prepad); |
189 | 189 | ||
190 | if (chip->ecc.prepad) { | 190 | if (chip->ecc.prepad) { |
191 | offset = (chip->ecc.steps - eccsteps) * chunk; | 191 | offset = (chip->ecc.steps - eccsteps) * chunk; |
192 | memcpy(&davinci_ecc_buf[offset], oob, chip->ecc.prepad); | 192 | memcpy(&davinci_ecc_buf[offset], oob, chip->ecc.prepad); |
193 | oob += chip->ecc.prepad; | 193 | oob += chip->ecc.prepad; |
194 | } | 194 | } |
195 | 195 | ||
196 | offset = ((chip->ecc.steps - eccsteps) * chunk) + | 196 | offset = ((chip->ecc.steps - eccsteps) * chunk) + |
197 | chip->ecc.prepad; | 197 | chip->ecc.prepad; |
198 | memcpy(&davinci_ecc_buf[offset], oob, eccbytes); | 198 | memcpy(&davinci_ecc_buf[offset], oob, eccbytes); |
199 | oob += eccbytes; | 199 | oob += eccbytes; |
200 | 200 | ||
201 | if (chip->ecc.postpad) { | 201 | if (chip->ecc.postpad) { |
202 | offset = ((chip->ecc.steps - eccsteps) * chunk) + | 202 | offset = ((chip->ecc.steps - eccsteps) * chunk) + |
203 | chip->ecc.prepad + eccbytes; | 203 | chip->ecc.prepad + eccbytes; |
204 | memcpy(&davinci_ecc_buf[offset], oob, | 204 | memcpy(&davinci_ecc_buf[offset], oob, |
205 | chip->ecc.postpad); | 205 | chip->ecc.postpad); |
206 | oob += chip->ecc.postpad; | 206 | oob += chip->ecc.postpad; |
207 | } | 207 | } |
208 | } | 208 | } |
209 | 209 | ||
210 | /* | 210 | /* |
211 | * Write the sparebytes into the page once | 211 | * Write the sparebytes into the page once |
212 | * all eccsteps have been covered | 212 | * all eccsteps have been covered |
213 | */ | 213 | */ |
214 | for (i = 0; i < mtd->oobsize; i++) | 214 | for (i = 0; i < mtd->oobsize; i++) |
215 | writeb(davinci_ecc_buf[i], this->IO_ADDR_W); | 215 | writeb(davinci_ecc_buf[i], this->IO_ADDR_W); |
216 | 216 | ||
217 | /* Calculate remaining oob bytes */ | 217 | /* Calculate remaining oob bytes */ |
218 | i = mtd->oobsize - (oob - chip->oob_poi); | 218 | i = mtd->oobsize - (oob - chip->oob_poi); |
219 | if (i) | 219 | if (i) |
220 | chip->write_buf(mtd, oob, i); | 220 | chip->write_buf(mtd, oob, i); |
221 | } | 221 | } |
222 | 222 | ||
223 | static int davinci_std_write_oob_syndrome(struct mtd_info *mtd, | 223 | static int davinci_std_write_oob_syndrome(struct mtd_info *mtd, |
224 | struct nand_chip *chip, int page) | 224 | struct nand_chip *chip, int page) |
225 | { | 225 | { |
226 | int pos, status = 0; | 226 | int pos, status = 0; |
227 | const uint8_t *bufpoi = chip->oob_poi; | 227 | const uint8_t *bufpoi = chip->oob_poi; |
228 | 228 | ||
229 | pos = mtd->writesize; | 229 | pos = mtd->writesize; |
230 | 230 | ||
231 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | 231 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); |
232 | 232 | ||
233 | chip->write_buf(mtd, bufpoi, mtd->oobsize); | 233 | chip->write_buf(mtd, bufpoi, mtd->oobsize); |
234 | 234 | ||
235 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | 235 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); |
236 | status = chip->waitfunc(mtd, chip); | 236 | status = chip->waitfunc(mtd, chip); |
237 | 237 | ||
238 | return status & NAND_STATUS_FAIL ? -1 : 0; | 238 | return status & NAND_STATUS_FAIL ? -1 : 0; |
239 | } | 239 | } |
240 | 240 | ||
241 | static int davinci_std_read_oob_syndrome(struct mtd_info *mtd, | 241 | static int davinci_std_read_oob_syndrome(struct mtd_info *mtd, |
242 | struct nand_chip *chip, int page, int sndcmd) | 242 | struct nand_chip *chip, int page, int sndcmd) |
243 | { | 243 | { |
244 | struct nand_chip *this = mtd->priv; | 244 | struct nand_chip *this = mtd->priv; |
245 | uint8_t *buf = chip->oob_poi; | 245 | uint8_t *buf = chip->oob_poi; |
246 | uint8_t *bufpoi = buf; | 246 | uint8_t *bufpoi = buf; |
247 | 247 | ||
248 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); | 248 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
249 | 249 | ||
250 | chip->read_buf(mtd, bufpoi, mtd->oobsize); | 250 | chip->read_buf(mtd, bufpoi, mtd->oobsize); |
251 | 251 | ||
252 | return 1; | 252 | return 1; |
253 | } | 253 | } |
254 | 254 | ||
255 | static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip) | 255 | static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip) |
256 | { | 256 | { |
257 | struct nand_chip *this = mtd->priv; | 257 | struct nand_chip *this = mtd->priv; |
258 | unsigned long wbase = (unsigned long) this->IO_ADDR_W; | 258 | unsigned long wbase = (unsigned long) this->IO_ADDR_W; |
259 | unsigned long rbase = (unsigned long) this->IO_ADDR_R; | 259 | unsigned long rbase = (unsigned long) this->IO_ADDR_R; |
260 | 260 | ||
261 | if (chip == 1) { | 261 | if (chip == 1) { |
262 | __set_bit(14, &wbase); | 262 | __set_bit(14, &wbase); |
263 | __set_bit(14, &rbase); | 263 | __set_bit(14, &rbase); |
264 | } else { | 264 | } else { |
265 | __clear_bit(14, &wbase); | 265 | __clear_bit(14, &wbase); |
266 | __clear_bit(14, &rbase); | 266 | __clear_bit(14, &rbase); |
267 | } | 267 | } |
268 | this->IO_ADDR_W = (void *)wbase; | 268 | this->IO_ADDR_W = (void *)wbase; |
269 | this->IO_ADDR_R = (void *)rbase; | 269 | this->IO_ADDR_R = (void *)rbase; |
270 | } | 270 | } |
271 | 271 | ||
272 | int board_nand_init(struct nand_chip *nand) | 272 | int board_nand_init(struct nand_chip *nand) |
273 | { | 273 | { |
274 | davinci_nand_init(nand); | 274 | davinci_nand_init(nand); |
275 | nand->select_chip = nand_dm365evm_select_chip; | 275 | nand->select_chip = nand_dm365evm_select_chip; |
276 | 276 | ||
277 | return 0; | 277 | return 0; |
278 | } | 278 | } |
279 | 279 | ||
280 | struct nand_ecc_ctrl org_ecc; | 280 | struct nand_ecc_ctrl org_ecc; |
281 | static int notsaved = 1; | 281 | static int notsaved = 1; |
282 | 282 | ||
283 | static int nand_switch_hw_func(int mode) | 283 | static int nand_switch_hw_func(int mode) |
284 | { | 284 | { |
285 | struct nand_chip *nand; | 285 | struct nand_chip *nand; |
286 | struct mtd_info *mtd; | 286 | struct mtd_info *mtd; |
287 | 287 | ||
288 | if (nand_curr_device < 0 || | 288 | if (nand_curr_device < 0 || |
289 | nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || | 289 | nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || |
290 | !nand_info[nand_curr_device].name) { | 290 | !nand_info[nand_curr_device].name) { |
291 | printf("Error: Can't switch hw functions," \ | 291 | printf("Error: Can't switch hw functions," \ |
292 | " no devices available\n"); | 292 | " no devices available\n"); |
293 | return -1; | 293 | return -1; |
294 | } | 294 | } |
295 | 295 | ||
296 | mtd = &nand_info[nand_curr_device]; | 296 | mtd = &nand_info[nand_curr_device]; |
297 | nand = mtd->priv; | 297 | nand = mtd->priv; |
298 | 298 | ||
299 | if (mode == 0) { | 299 | if (mode == 0) { |
300 | if (notsaved == 0) { | 300 | if (notsaved == 0) { |
301 | printf("switching to uboot hw functions.\n"); | 301 | printf("switching to uboot hw functions.\n"); |
302 | memcpy(&nand->ecc, &org_ecc, | 302 | memcpy(&nand->ecc, &org_ecc, |
303 | sizeof(struct nand_ecc_ctrl)); | 303 | sizeof(struct nand_ecc_ctrl)); |
304 | } | 304 | } |
305 | } else { | 305 | } else { |
306 | /* RBL */ | 306 | /* RBL */ |
307 | printf("switching to RBL hw functions.\n"); | 307 | printf("switching to RBL hw functions.\n"); |
308 | if (notsaved == 1) { | 308 | if (notsaved == 1) { |
309 | memcpy(&org_ecc, &nand->ecc, | 309 | memcpy(&org_ecc, &nand->ecc, |
310 | sizeof(struct nand_ecc_ctrl)); | 310 | sizeof(struct nand_ecc_ctrl)); |
311 | notsaved = 0; | 311 | notsaved = 0; |
312 | } | 312 | } |
313 | nand->ecc.mode = NAND_ECC_HW_SYNDROME; | 313 | nand->ecc.mode = NAND_ECC_HW_SYNDROME; |
314 | nand->ecc.prepad = 6; | 314 | nand->ecc.prepad = 6; |
315 | nand->ecc.read_page = davinci_std_read_page_syndrome; | 315 | nand->ecc.read_page = davinci_std_read_page_syndrome; |
316 | nand->ecc.write_page = davinci_std_write_page_syndrome; | 316 | nand->ecc.write_page = davinci_std_write_page_syndrome; |
317 | nand->ecc.read_oob = davinci_std_read_oob_syndrome; | 317 | nand->ecc.read_oob = davinci_std_read_oob_syndrome; |
318 | nand->ecc.write_oob = davinci_std_write_oob_syndrome; | 318 | nand->ecc.write_oob = davinci_std_write_oob_syndrome; |
319 | } | 319 | } |
320 | return mode; | 320 | return mode; |
321 | } | 321 | } |
322 | 322 | ||
323 | static int hwmode; | 323 | static int hwmode; |
324 | 324 | ||
325 | static int do_switch_ecc(cmd_tbl_t *cmdtp, int flag, int argc, | 325 | static int do_switch_ecc(cmd_tbl_t *cmdtp, int flag, int argc, |
326 | char *const argv[]) | 326 | char *const argv[]) |
327 | { | 327 | { |
328 | if (argc != 2) | 328 | if (argc != 2) |
329 | goto usage; | 329 | goto usage; |
330 | if (strncmp(argv[1], "rbl", 2) == 0) | 330 | if (strncmp(argv[1], "rbl", 2) == 0) |
331 | hwmode = nand_switch_hw_func(1); | 331 | hwmode = nand_switch_hw_func(1); |
332 | else if (strncmp(argv[1], "uboot", 2) == 0) | 332 | else if (strncmp(argv[1], "uboot", 2) == 0) |
333 | hwmode = nand_switch_hw_func(0); | 333 | hwmode = nand_switch_hw_func(0); |
334 | else | 334 | else |
335 | goto usage; | 335 | goto usage; |
336 | 336 | ||
337 | return 0; | 337 | return 0; |
338 | 338 | ||
339 | usage: | 339 | usage: |
340 | printf("Usage: nandrbl %s\n", cmdtp->usage); | 340 | printf("Usage: nandrbl %s\n", cmdtp->usage); |
341 | return 1; | 341 | return 1; |
342 | } | 342 | } |
343 | 343 | ||
344 | U_BOOT_CMD( | 344 | U_BOOT_CMD( |
345 | nandrbl, 2, 1, do_switch_ecc, | 345 | nandrbl, 2, 1, do_switch_ecc, |
346 | "switch between rbl/uboot NAND ECC calculation algorithm", | 346 | "switch between rbl/uboot NAND ECC calculation algorithm", |
347 | "[rbl/uboot] - Switch between rbl/uboot NAND ECC algorithm" | 347 | "[rbl/uboot] - Switch between rbl/uboot NAND ECC algorithm" |
348 | ); | 348 | ); |
349 | 349 | ||
350 | 350 | ||
351 | #endif /* #ifdef CONFIG_NAND_DAVINCI */ | 351 | #endif /* #ifdef CONFIG_NAND_DAVINCI */ |
352 | 352 | ||
353 | #ifdef CONFIG_DAVINCI_MMC | 353 | #ifdef CONFIG_DAVINCI_MMC |
354 | static struct davinci_mmc mmc_sd0 = { | 354 | static struct davinci_mmc mmc_sd0 = { |
355 | .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD0_BASE, | 355 | .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD0_BASE, |
356 | .input_clk = 121500000, | 356 | .input_clk = 121500000, |
357 | .host_caps = MMC_MODE_4BIT, | 357 | .host_caps = MMC_MODE_4BIT, |
358 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, | 358 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, |
359 | .version = MMC_CTLR_VERSION_2, | 359 | .version = MMC_CTLR_VERSION_2, |
360 | }; | 360 | }; |
361 | 361 | ||
362 | int board_mmc_init(bd_t *bis) | 362 | int board_mmc_init(bd_t *bis) |
363 | { | 363 | { |
364 | int err; | 364 | int err; |
365 | 365 | ||
366 | /* Add slot-0 to mmc subsystem */ | 366 | /* Add slot-0 to mmc subsystem */ |
367 | err = davinci_mmc_init(bis, &mmc_sd0); | 367 | err = davinci_mmc_init(bis, &mmc_sd0); |
368 | 368 | ||
369 | return err; | 369 | return err; |
370 | } | 370 | } |
371 | #endif | 371 | #endif |
372 | 372 | ||
373 | int board_late_init(void) | 373 | int board_late_init(void) |
374 | { | 374 | { |
375 | struct davinci_gpio *gpio = davinci_gpio_bank45; | 375 | struct davinci_gpio *gpio = davinci_gpio_bank45; |
376 | 376 | ||
377 | /* 24MHz InputClock / 15 prediv -> 1.6 MHz timer running */ | 377 | /* 24MHz InputClock / 15 prediv -> 1.6 MHz timer running */ |
378 | while ((get_timer_val() < CONFIG_AIT_TIMER_TIMEOUT) && | 378 | while ((get_timer_val() < CONFIG_AIT_TIMER_TIMEOUT) && |
379 | timer_running()) | 379 | timer_running()) |
380 | ; | 380 | ; |
381 | 381 | ||
382 | /* 1 sec reached -> stop timer, clear all LED */ | 382 | /* 1 sec reached -> stop timer, clear all LED */ |
383 | stop_timer(); | 383 | stop_timer(); |
384 | clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); | 384 | clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
385 | return 0; | 385 | return 0; |
386 | } | 386 | } |
387 | 387 | ||
388 | void reset_phy(void) | 388 | void reset_phy(void) |
389 | { | 389 | { |
390 | char *name = "GENERIC @ 0x00"; | 390 | char *name = "GENERIC @ 0x00"; |
391 | 391 | ||
392 | /* reset the phy */ | 392 | /* reset the phy */ |
393 | miiphy_reset(name, 0x0); | 393 | miiphy_reset(name, 0x0); |
394 | } | 394 | } |
395 | 395 | ||
396 | #else /* #ifndef CONFIG_SPL_BUILD */ | 396 | #else /* #ifndef CONFIG_SPL_BUILD */ |
397 | static void cam_enc_4xx_set_all_led(void) | 397 | static void cam_enc_4xx_set_all_led(void) |
398 | { | 398 | { |
399 | struct davinci_gpio *gpio = davinci_gpio_bank45; | 399 | struct davinci_gpio *gpio = davinci_gpio_bank45; |
400 | 400 | ||
401 | setbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); | 401 | setbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
402 | } | 402 | } |
403 | 403 | ||
404 | /* | 404 | /* |
405 | * TIMER 0 is used for tick | 405 | * TIMER 0 is used for tick |
406 | */ | 406 | */ |
407 | static struct davinci_timer *timer = | 407 | static struct davinci_timer *timer = |
408 | (struct davinci_timer *)DAVINCI_TIMER3_BASE; | 408 | (struct davinci_timer *)DAVINCI_TIMER3_BASE; |
409 | 409 | ||
410 | #define TIMER_LOAD_VAL 0xffffffff | 410 | #define TIMER_LOAD_VAL 0xffffffff |
411 | #define TIM_CLK_DIV 16 | 411 | #define TIM_CLK_DIV 16 |
412 | 412 | ||
413 | static int cam_enc_4xx_timer_init(void) | 413 | static int cam_enc_4xx_timer_init(void) |
414 | { | 414 | { |
415 | /* We are using timer34 in unchained 32-bit mode, full speed */ | 415 | /* We are using timer34 in unchained 32-bit mode, full speed */ |
416 | writel(0x0, &timer->tcr); | 416 | writel(0x0, &timer->tcr); |
417 | writel(0x0, &timer->tgcr); | 417 | writel(0x0, &timer->tgcr); |
418 | writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr); | 418 | writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr); |
419 | writel(0x0, &timer->tim34); | 419 | writel(0x0, &timer->tim34); |
420 | writel(TIMER_LOAD_VAL, &timer->prd34); | 420 | writel(TIMER_LOAD_VAL, &timer->prd34); |
421 | writel(2 << 22, &timer->tcr); | 421 | writel(2 << 22, &timer->tcr); |
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | void board_gpio_init(void) | 425 | void board_gpio_init(void) |
426 | { | 426 | { |
427 | struct davinci_gpio *gpio; | 427 | struct davinci_gpio *gpio; |
428 | 428 | ||
429 | cam_enc_4xx_set_all_led(); | 429 | cam_enc_4xx_set_all_led(); |
430 | cam_enc_4xx_timer_init(); | 430 | cam_enc_4xx_timer_init(); |
431 | gpio = davinci_gpio_bank01; | 431 | gpio = davinci_gpio_bank01; |
432 | clrbits_le32(&gpio->dir, ~0xfdfffffe); | 432 | clrbits_le32(&gpio->dir, ~0xfdfffffe); |
433 | /* clear LED D14 = GPIO25 */ | 433 | /* clear LED D14 = GPIO25 */ |
434 | clrbits_le32(&gpio->out_data, 0x02000000); | 434 | clrbits_le32(&gpio->out_data, 0x02000000); |
435 | gpio = davinci_gpio_bank23; | 435 | gpio = davinci_gpio_bank23; |
436 | clrbits_le32(&gpio->dir, ~0x5ff0afef); | 436 | clrbits_le32(&gpio->dir, ~0x5ff0afef); |
437 | /* set GPIO61 to 1 -> intern UART0 as Console */ | 437 | /* set GPIO61 to 1 -> intern UART0 as Console */ |
438 | setbits_le32(&gpio->out_data, 0x20000000); | 438 | setbits_le32(&gpio->out_data, 0x20000000); |
439 | /* | 439 | /* |
440 | * PHY out of reset GIO 50 = 1 | 440 | * PHY out of reset GIO 50 = 1 |
441 | * NAND WP off GIO 51 = 1 | 441 | * NAND WP off GIO 51 = 1 |
442 | */ | 442 | */ |
443 | setbits_le32(&gpio->out_data, 0x000c0004); | 443 | setbits_le32(&gpio->out_data, 0x000c0004); |
444 | gpio = davinci_gpio_bank45; | 444 | gpio = davinci_gpio_bank45; |
445 | clrbits_le32(&gpio->dir, ~(0xdb2fffff) | CONFIG_CAM_ENC_LED_MASK); | 445 | clrbits_le32(&gpio->dir, ~(0xdb2fffff) | CONFIG_CAM_ENC_LED_MASK); |
446 | /* | 446 | /* |
447 | * clear LED: | 447 | * clear LED: |
448 | * D17 = GPIO86 | 448 | * D17 = GPIO86 |
449 | * D11 = GPIO87 | 449 | * D11 = GPIO87 |
450 | * GPIO88 | 450 | * GPIO88 |
451 | * GPIO89 | 451 | * GPIO89 |
452 | * D13 = GPIO90 | 452 | * D13 = GPIO90 |
453 | * GPIO91 | 453 | * GPIO91 |
454 | */ | 454 | */ |
455 | clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); | 455 | clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
456 | gpio = davinci_gpio_bank67; | 456 | gpio = davinci_gpio_bank67; |
457 | clrbits_le32(&gpio->dir, ~0x000007ff); | 457 | clrbits_le32(&gpio->dir, ~0x000007ff); |
458 | } | 458 | } |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * functions for the post memory test. | 461 | * functions for the post memory test. |
462 | */ | 462 | */ |
463 | int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) | 463 | int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) |
464 | { | 464 | { |
465 | *vstart = CONFIG_SYS_SDRAM_BASE; | 465 | *vstart = CONFIG_SYS_SDRAM_BASE; |
466 | *size = PHYS_SDRAM_1_SIZE; | 466 | *size = PHYS_SDRAM_1_SIZE; |
467 | *phys_offset = 0; | 467 | *phys_offset = 0; |
468 | return 0; | 468 | return 0; |
469 | } | 469 | } |
470 | 470 | ||
471 | void arch_memory_failure_handle(void) | 471 | void arch_memory_failure_handle(void) |
472 | { | 472 | { |
473 | cam_enc_4xx_set_all_led(); | 473 | cam_enc_4xx_set_all_led(); |
474 | puts("mem failure\n"); | 474 | puts("mem failure\n"); |
475 | while (1) | 475 | while (1) |
476 | ; | 476 | ; |
477 | } | 477 | } |
478 | #endif | 478 | #endif |
479 | #if defined(CONFIG_MENU) | 479 | #if defined(CONFIG_MENU) |
480 | #include "menu.h" | 480 | #include "menu.h" |
481 | 481 | ||
482 | #define MENU_EXIT -1 | 482 | #define MENU_EXIT -1 |
483 | #define MENU_EXIT_BOOTCMD -2 | 483 | #define MENU_EXIT_BOOTCMD -2 |
484 | #define MENU_STAY 0 | 484 | #define MENU_STAY 0 |
485 | #define MENU_MAIN 1 | 485 | #define MENU_MAIN 1 |
486 | #define MENU_UPDATE 2 | 486 | #define MENU_UPDATE 2 |
487 | #define MENU_NETWORK 3 | 487 | #define MENU_NETWORK 3 |
488 | #define MENU_LOAD 4 | 488 | #define MENU_LOAD 4 |
489 | 489 | ||
490 | static int menu_start; | 490 | static int menu_start; |
491 | 491 | ||
492 | #define FIT_SUBTYPE_UNKNOWN 0 | 492 | #define FIT_SUBTYPE_UNKNOWN 0 |
493 | #define FIT_SUBTYPE_UBL_HEADER 1 | 493 | #define FIT_SUBTYPE_UBL_HEADER 1 |
494 | #define FIT_SUBTYPE_SPL_IMAGE 2 | 494 | #define FIT_SUBTYPE_SPL_IMAGE 2 |
495 | #define FIT_SUBTYPE_UBOOT_IMAGE 3 | 495 | #define FIT_SUBTYPE_UBOOT_IMAGE 3 |
496 | #define FIT_SUBTYPE_DF_ENV_IMAGE 4 | 496 | #define FIT_SUBTYPE_DF_ENV_IMAGE 4 |
497 | #define FIT_SUBTYPE_RAMDISK_IMAGE 5 | 497 | #define FIT_SUBTYPE_RAMDISK_IMAGE 5 |
498 | 498 | ||
499 | struct fit_images_info { | 499 | struct fit_images_info { |
500 | u_int8_t type; | 500 | u_int8_t type; |
501 | int subtype; | 501 | int subtype; |
502 | char desc[200]; | 502 | char desc[200]; |
503 | const void *data; | 503 | const void *data; |
504 | size_t size; | 504 | size_t size; |
505 | }; | 505 | }; |
506 | 506 | ||
507 | static struct fit_images_info imgs[10]; | 507 | static struct fit_images_info imgs[10]; |
508 | 508 | ||
509 | struct menu_display { | 509 | struct menu_display { |
510 | char title[50]; | 510 | char title[50]; |
511 | int timeout; /* in sec */ | 511 | int timeout; /* in sec */ |
512 | int id; /* MENU_* */ | 512 | int id; /* MENU_* */ |
513 | char **menulist; | 513 | char **menulist; |
514 | int (*menu_evaluate)(char *choice); | 514 | int (*menu_evaluate)(char *choice); |
515 | }; | 515 | }; |
516 | 516 | ||
517 | char *menu_main[] = { | 517 | char *menu_main[] = { |
518 | "(1) Boot", | 518 | "(1) Boot", |
519 | "(2) Update Software", | 519 | "(2) Update Software", |
520 | "(3) Reset to default setting and boot", | 520 | "(3) Reset to default setting and boot", |
521 | "(4) Enter U-Boot console", | 521 | "(4) Enter U-Boot console", |
522 | NULL | 522 | NULL |
523 | }; | 523 | }; |
524 | 524 | ||
525 | char *menu_update[] = { | 525 | char *menu_update[] = { |
526 | "(1) Network settings", | 526 | "(1) Network settings", |
527 | "(2) load image", | 527 | "(2) load image", |
528 | "(3) back to main", | 528 | "(3) back to main", |
529 | NULL | 529 | NULL |
530 | }; | 530 | }; |
531 | 531 | ||
532 | char *menu_load[] = { | 532 | char *menu_load[] = { |
533 | "(1) install image", | 533 | "(1) install image", |
534 | "(2) cancel", | 534 | "(2) cancel", |
535 | NULL | 535 | NULL |
536 | }; | 536 | }; |
537 | 537 | ||
538 | char *menu_network[] = { | 538 | char *menu_network[] = { |
539 | "(1) ipaddr ", | 539 | "(1) ipaddr ", |
540 | "(2) netmask ", | 540 | "(2) netmask ", |
541 | "(3) serverip ", | 541 | "(3) serverip ", |
542 | "(4) gatewayip", | 542 | "(4) gatewayip", |
543 | "(5) tftp image name", | 543 | "(5) tftp image name", |
544 | "(6) back to update software", | 544 | "(6) back to update software", |
545 | NULL | 545 | NULL |
546 | }; | 546 | }; |
547 | 547 | ||
548 | static void ait_menu_print(void *data) | 548 | static void ait_menu_print(void *data) |
549 | { | 549 | { |
550 | printf("%s\n", (char *)data); | 550 | printf("%s\n", (char *)data); |
551 | return; | 551 | return; |
552 | } | 552 | } |
553 | 553 | ||
554 | static char *menu_handle(struct menu_display *display) | 554 | static char *menu_handle(struct menu_display *display) |
555 | { | 555 | { |
556 | struct menu *m; | 556 | struct menu *m; |
557 | int i; | 557 | int i; |
558 | void *choice = NULL; | 558 | void *choice = NULL; |
559 | char key[2]; | 559 | char key[2]; |
560 | int ret; | 560 | int ret; |
561 | char *s; | 561 | char *s; |
562 | char temp[6][200]; | 562 | char temp[6][200]; |
563 | 563 | ||
564 | m = menu_create(display->title, display->timeout, 1, ait_menu_print); | 564 | m = menu_create(display->title, display->timeout, 1, ait_menu_print, |
565 | NULL, NULL); | ||
565 | 566 | ||
566 | for (i = 0; display->menulist[i]; i++) { | 567 | for (i = 0; display->menulist[i]; i++) { |
567 | sprintf(key, "%d", i + 1); | 568 | sprintf(key, "%d", i + 1); |
568 | if (display->id == MENU_NETWORK) { | 569 | if (display->id == MENU_NETWORK) { |
569 | switch (i) { | 570 | switch (i) { |
570 | case 0: | 571 | case 0: |
571 | s = getenv("ipaddr"); | 572 | s = getenv("ipaddr"); |
572 | break; | 573 | break; |
573 | case 1: | 574 | case 1: |
574 | s = getenv("netmask"); | 575 | s = getenv("netmask"); |
575 | break; | 576 | break; |
576 | case 2: | 577 | case 2: |
577 | s = getenv("serverip"); | 578 | s = getenv("serverip"); |
578 | break; | 579 | break; |
579 | case 3: | 580 | case 3: |
580 | s = getenv("gatewayip"); | 581 | s = getenv("gatewayip"); |
581 | break; | 582 | break; |
582 | case 4: | 583 | case 4: |
583 | s = getenv("img_file"); | 584 | s = getenv("img_file"); |
584 | break; | 585 | break; |
585 | default: | 586 | default: |
586 | s = NULL; | 587 | s = NULL; |
587 | break; | 588 | break; |
588 | } | 589 | } |
589 | if (s) { | 590 | if (s) { |
590 | sprintf(temp[i], "%s: %s", | 591 | sprintf(temp[i], "%s: %s", |
591 | display->menulist[i], s); | 592 | display->menulist[i], s); |
592 | ret = menu_item_add(m, key, temp[i]); | 593 | ret = menu_item_add(m, key, temp[i]); |
593 | } else { | 594 | } else { |
594 | ret = menu_item_add(m, key, | 595 | ret = menu_item_add(m, key, |
595 | display->menulist[i]); | 596 | display->menulist[i]); |
596 | } | 597 | } |
597 | } else { | 598 | } else { |
598 | ret = menu_item_add(m, key, display->menulist[i]); | 599 | ret = menu_item_add(m, key, display->menulist[i]); |
599 | } | 600 | } |
600 | 601 | ||
601 | if (ret != 1) { | 602 | if (ret != 1) { |
602 | printf("failed to add item!"); | 603 | printf("failed to add item!"); |
603 | menu_destroy(m); | 604 | menu_destroy(m); |
604 | return NULL; | 605 | return NULL; |
605 | } | 606 | } |
606 | } | 607 | } |
607 | sprintf(key, "%d", 1); | 608 | sprintf(key, "%d", 1); |
608 | menu_default_set(m, key); | 609 | menu_default_set(m, key); |
609 | 610 | ||
610 | if (menu_get_choice(m, &choice) != 1) | 611 | if (menu_get_choice(m, &choice) != 1) |
611 | debug("Problem picking a choice!\n"); | 612 | debug("Problem picking a choice!\n"); |
612 | 613 | ||
613 | menu_destroy(m); | 614 | menu_destroy(m); |
614 | 615 | ||
615 | return choice; | 616 | return choice; |
616 | } | 617 | } |
617 | 618 | ||
618 | static int ait_menu_show(struct menu_display *display, int bootdelay) | 619 | static int ait_menu_show(struct menu_display *display, int bootdelay) |
619 | { | 620 | { |
620 | int end = MENU_STAY; | 621 | int end = MENU_STAY; |
621 | char *choice; | 622 | char *choice; |
622 | 623 | ||
623 | if ((menu_start == 0) && (display->id == MENU_MAIN)) | 624 | if ((menu_start == 0) && (display->id == MENU_MAIN)) |
624 | display->timeout = bootdelay; | 625 | display->timeout = bootdelay; |
625 | else | 626 | else |
626 | display->timeout = 0; | 627 | display->timeout = 0; |
627 | 628 | ||
628 | while (end == MENU_STAY) { | 629 | while (end == MENU_STAY) { |
629 | choice = menu_handle(display); | 630 | choice = menu_handle(display); |
630 | if (choice) | 631 | if (choice) |
631 | end = display->menu_evaluate(choice); | 632 | end = display->menu_evaluate(choice); |
632 | 633 | ||
633 | if (end == display->id) | 634 | if (end == display->id) |
634 | end = MENU_STAY; | 635 | end = MENU_STAY; |
635 | if (display->id == MENU_MAIN) { | 636 | if (display->id == MENU_MAIN) { |
636 | if (menu_start == 0) | 637 | if (menu_start == 0) |
637 | end = MENU_EXIT_BOOTCMD; | 638 | end = MENU_EXIT_BOOTCMD; |
638 | else | 639 | else |
639 | display->timeout = 0; | 640 | display->timeout = 0; |
640 | } | 641 | } |
641 | } | 642 | } |
642 | return end; | 643 | return end; |
643 | } | 644 | } |
644 | 645 | ||
645 | static int ait_writeublheader(void) | 646 | static int ait_writeublheader(void) |
646 | { | 647 | { |
647 | char s[20]; | 648 | char s[20]; |
648 | unsigned long i; | 649 | unsigned long i; |
649 | int ret; | 650 | int ret; |
650 | 651 | ||
651 | for (i = CONFIG_SYS_NAND_BLOCK_SIZE; | 652 | for (i = CONFIG_SYS_NAND_BLOCK_SIZE; |
652 | i < CONFIG_SYS_NAND_U_BOOT_OFFS; | 653 | i < CONFIG_SYS_NAND_U_BOOT_OFFS; |
653 | i += CONFIG_SYS_NAND_BLOCK_SIZE) { | 654 | i += CONFIG_SYS_NAND_BLOCK_SIZE) { |
654 | sprintf(s, "%lx", i); | 655 | sprintf(s, "%lx", i); |
655 | ret = setenv("header_addr", s); | 656 | ret = setenv("header_addr", s); |
656 | if (ret == 0) | 657 | if (ret == 0) |
657 | ret = run_command("run img_writeheader", 0); | 658 | ret = run_command("run img_writeheader", 0); |
658 | if (ret != 0) | 659 | if (ret != 0) |
659 | break; | 660 | break; |
660 | } | 661 | } |
661 | return ret; | 662 | return ret; |
662 | } | 663 | } |
663 | 664 | ||
664 | static int ait_menu_install_images(void) | 665 | static int ait_menu_install_images(void) |
665 | { | 666 | { |
666 | int ret = 0; | 667 | int ret = 0; |
667 | int count = 0; | 668 | int count = 0; |
668 | char s[100]; | 669 | char s[100]; |
669 | char *t; | 670 | char *t; |
670 | 671 | ||
671 | /* | 672 | /* |
672 | * possible image types: | 673 | * possible image types: |
673 | * FIT_SUBTYPE_UNKNOWN | 674 | * FIT_SUBTYPE_UNKNOWN |
674 | * FIT_SUBTYPE_UBL_HEADER | 675 | * FIT_SUBTYPE_UBL_HEADER |
675 | * FIT_SUBTYPE_SPL_IMAGE | 676 | * FIT_SUBTYPE_SPL_IMAGE |
676 | * FIT_SUBTYPE_UBOOT_IMAGE | 677 | * FIT_SUBTYPE_UBOOT_IMAGE |
677 | * FIT_SUBTYPE_DF_ENV_IMAGE | 678 | * FIT_SUBTYPE_DF_ENV_IMAGE |
678 | * FIT_SUBTYPE_RAMDISK_IMAGE | 679 | * FIT_SUBTYPE_RAMDISK_IMAGE |
679 | * | 680 | * |
680 | * use Envvariables: | 681 | * use Envvariables: |
681 | * img_addr_r: image start addr | 682 | * img_addr_r: image start addr |
682 | * header_addr: addr where to write to UBL header | 683 | * header_addr: addr where to write to UBL header |
683 | * img_writeheader: write ubl header to nand | 684 | * img_writeheader: write ubl header to nand |
684 | * img_writespl: write spl to nand | 685 | * img_writespl: write spl to nand |
685 | * img_writeuboot: write uboot to nand | 686 | * img_writeuboot: write uboot to nand |
686 | * img_writedfenv: write default environment to ubi volume | 687 | * img_writedfenv: write default environment to ubi volume |
687 | * img_volume: which ubi volume should be updated with img_writeramdisk | 688 | * img_volume: which ubi volume should be updated with img_writeramdisk |
688 | * filesize: size of data for updating ubi volume | 689 | * filesize: size of data for updating ubi volume |
689 | * img_writeramdisk: write ramdisk to ubi volume | 690 | * img_writeramdisk: write ramdisk to ubi volume |
690 | */ | 691 | */ |
691 | 692 | ||
692 | while (imgs[count].type != IH_TYPE_INVALID) { | 693 | while (imgs[count].type != IH_TYPE_INVALID) { |
693 | printf("Installing %s\n", | 694 | printf("Installing %s\n", |
694 | genimg_get_type_name(imgs[count].type)); | 695 | genimg_get_type_name(imgs[count].type)); |
695 | sprintf(s, "%p", imgs[count].data); | 696 | sprintf(s, "%p", imgs[count].data); |
696 | setenv("img_addr_r", s); | 697 | setenv("img_addr_r", s); |
697 | sprintf(s, "%lx", (unsigned long)imgs[count].size); | 698 | sprintf(s, "%lx", (unsigned long)imgs[count].size); |
698 | setenv("filesize", s); | 699 | setenv("filesize", s); |
699 | switch (imgs[count].subtype) { | 700 | switch (imgs[count].subtype) { |
700 | case FIT_SUBTYPE_DF_ENV_IMAGE: | 701 | case FIT_SUBTYPE_DF_ENV_IMAGE: |
701 | ret = run_command("run img_writedfenv", 0); | 702 | ret = run_command("run img_writedfenv", 0); |
702 | break; | 703 | break; |
703 | case FIT_SUBTYPE_RAMDISK_IMAGE: | 704 | case FIT_SUBTYPE_RAMDISK_IMAGE: |
704 | t = getenv("img_volume"); | 705 | t = getenv("img_volume"); |
705 | if (!t) { | 706 | if (!t) { |
706 | ret = setenv("img_volume", "rootfs1"); | 707 | ret = setenv("img_volume", "rootfs1"); |
707 | } else { | 708 | } else { |
708 | /* switch to other volume */ | 709 | /* switch to other volume */ |
709 | if (strncmp(t, "rootfs1", 7) == 0) | 710 | if (strncmp(t, "rootfs1", 7) == 0) |
710 | ret = setenv("img_volume", "rootfs2"); | 711 | ret = setenv("img_volume", "rootfs2"); |
711 | else | 712 | else |
712 | ret = setenv("img_volume", "rootfs1"); | 713 | ret = setenv("img_volume", "rootfs1"); |
713 | } | 714 | } |
714 | if (ret != 0) | 715 | if (ret != 0) |
715 | break; | 716 | break; |
716 | 717 | ||
717 | ret = run_command("run img_writeramdisk", 0); | 718 | ret = run_command("run img_writeramdisk", 0); |
718 | break; | 719 | break; |
719 | case FIT_SUBTYPE_SPL_IMAGE: | 720 | case FIT_SUBTYPE_SPL_IMAGE: |
720 | ret = run_command("run img_writespl", 0); | 721 | ret = run_command("run img_writespl", 0); |
721 | break; | 722 | break; |
722 | case FIT_SUBTYPE_UBL_HEADER: | 723 | case FIT_SUBTYPE_UBL_HEADER: |
723 | ret = ait_writeublheader(); | 724 | ret = ait_writeublheader(); |
724 | break; | 725 | break; |
725 | case FIT_SUBTYPE_UBOOT_IMAGE: | 726 | case FIT_SUBTYPE_UBOOT_IMAGE: |
726 | ret = run_command("run img_writeuboot", 0); | 727 | ret = run_command("run img_writeuboot", 0); |
727 | break; | 728 | break; |
728 | default: | 729 | default: |
729 | /* not supported type */ | 730 | /* not supported type */ |
730 | break; | 731 | break; |
731 | } | 732 | } |
732 | count++; | 733 | count++; |
733 | } | 734 | } |
734 | /* now save dvn_* and img_volume env vars to new values */ | 735 | /* now save dvn_* and img_volume env vars to new values */ |
735 | if (ret == 0) { | 736 | if (ret == 0) { |
736 | t = getenv("x_dvn_boot_vers"); | 737 | t = getenv("x_dvn_boot_vers"); |
737 | if (t) | 738 | if (t) |
738 | setenv("dvn_boot_vers", t); | 739 | setenv("dvn_boot_vers", t); |
739 | 740 | ||
740 | t = getenv("x_dvn_app_vers"); | 741 | t = getenv("x_dvn_app_vers"); |
741 | if (t) | 742 | if (t) |
742 | setenv("dvn_boot_vers", t); | 743 | setenv("dvn_boot_vers", t); |
743 | 744 | ||
744 | setenv("x_dvn_boot_vers", NULL); | 745 | setenv("x_dvn_boot_vers", NULL); |
745 | setenv("x_dvn_app_vers", NULL); | 746 | setenv("x_dvn_app_vers", NULL); |
746 | ret = run_command("run savenewvers", 0); | 747 | ret = run_command("run savenewvers", 0); |
747 | } | 748 | } |
748 | 749 | ||
749 | return ret; | 750 | return ret; |
750 | } | 751 | } |
751 | 752 | ||
752 | static int ait_menu_evaluate_load(char *choice) | 753 | static int ait_menu_evaluate_load(char *choice) |
753 | { | 754 | { |
754 | if (!choice) | 755 | if (!choice) |
755 | return -1; | 756 | return -1; |
756 | 757 | ||
757 | switch (choice[1]) { | 758 | switch (choice[1]) { |
758 | case '1': | 759 | case '1': |
759 | /* install image */ | 760 | /* install image */ |
760 | ait_menu_install_images(); | 761 | ait_menu_install_images(); |
761 | break; | 762 | break; |
762 | case '2': | 763 | case '2': |
763 | /* cancel, back to main */ | 764 | /* cancel, back to main */ |
764 | setenv("x_dvn_boot_vers", NULL); | 765 | setenv("x_dvn_boot_vers", NULL); |
765 | setenv("x_dvn_app_vers", NULL); | 766 | setenv("x_dvn_app_vers", NULL); |
766 | break; | 767 | break; |
767 | } | 768 | } |
768 | 769 | ||
769 | return MENU_MAIN; | 770 | return MENU_MAIN; |
770 | } | 771 | } |
771 | 772 | ||
772 | struct menu_display ait_load = { | 773 | struct menu_display ait_load = { |
773 | .title = "AIT load image", | 774 | .title = "AIT load image", |
774 | .timeout = 0, | 775 | .timeout = 0, |
775 | .id = MENU_LOAD, | 776 | .id = MENU_LOAD, |
776 | .menulist = menu_load, | 777 | .menulist = menu_load, |
777 | .menu_evaluate = ait_menu_evaluate_load, | 778 | .menu_evaluate = ait_menu_evaluate_load, |
778 | }; | 779 | }; |
779 | 780 | ||
780 | static void ait_menu_read_env(char *name) | 781 | static void ait_menu_read_env(char *name) |
781 | { | 782 | { |
782 | char output[CONFIG_SYS_CBSIZE]; | 783 | char output[CONFIG_SYS_CBSIZE]; |
783 | char cbuf[CONFIG_SYS_CBSIZE]; | 784 | char cbuf[CONFIG_SYS_CBSIZE]; |
784 | int readret; | 785 | int readret; |
785 | int ret; | 786 | int ret; |
786 | 787 | ||
787 | sprintf(output, "%s old: %s value: ", name, getenv(name)); | 788 | sprintf(output, "%s old: %s value: ", name, getenv(name)); |
788 | memset(cbuf, 0, CONFIG_SYS_CBSIZE); | 789 | memset(cbuf, 0, CONFIG_SYS_CBSIZE); |
789 | readret = readline_into_buffer(output, cbuf, 0); | 790 | readret = readline_into_buffer(output, cbuf, 0); |
790 | 791 | ||
791 | if (readret >= 0) { | 792 | if (readret >= 0) { |
792 | ret = setenv(name, cbuf); | 793 | ret = setenv(name, cbuf); |
793 | if (ret) { | 794 | if (ret) { |
794 | printf("Error setting %s\n", name); | 795 | printf("Error setting %s\n", name); |
795 | return; | 796 | return; |
796 | } | 797 | } |
797 | } | 798 | } |
798 | return; | 799 | return; |
799 | } | 800 | } |
800 | 801 | ||
801 | static int ait_menu_evaluate_network(char *choice) | 802 | static int ait_menu_evaluate_network(char *choice) |
802 | { | 803 | { |
803 | if (!choice) | 804 | if (!choice) |
804 | return MENU_MAIN; | 805 | return MENU_MAIN; |
805 | 806 | ||
806 | switch (choice[1]) { | 807 | switch (choice[1]) { |
807 | case '1': | 808 | case '1': |
808 | ait_menu_read_env("ipaddr"); | 809 | ait_menu_read_env("ipaddr"); |
809 | break; | 810 | break; |
810 | case '2': | 811 | case '2': |
811 | ait_menu_read_env("netmask"); | 812 | ait_menu_read_env("netmask"); |
812 | break; | 813 | break; |
813 | case '3': | 814 | case '3': |
814 | ait_menu_read_env("serverip"); | 815 | ait_menu_read_env("serverip"); |
815 | break; | 816 | break; |
816 | case '4': | 817 | case '4': |
817 | ait_menu_read_env("gatewayip"); | 818 | ait_menu_read_env("gatewayip"); |
818 | break; | 819 | break; |
819 | case '5': | 820 | case '5': |
820 | ait_menu_read_env("img_file"); | 821 | ait_menu_read_env("img_file"); |
821 | break; | 822 | break; |
822 | case '6': | 823 | case '6': |
823 | return MENU_UPDATE; | 824 | return MENU_UPDATE; |
824 | break; | 825 | break; |
825 | } | 826 | } |
826 | 827 | ||
827 | return MENU_STAY; | 828 | return MENU_STAY; |
828 | } | 829 | } |
829 | 830 | ||
830 | struct menu_display ait_network = { | 831 | struct menu_display ait_network = { |
831 | .title = "AIT network settings", | 832 | .title = "AIT network settings", |
832 | .timeout = 0, | 833 | .timeout = 0, |
833 | .id = MENU_NETWORK, | 834 | .id = MENU_NETWORK, |
834 | .menulist = menu_network, | 835 | .menulist = menu_network, |
835 | .menu_evaluate = ait_menu_evaluate_network, | 836 | .menu_evaluate = ait_menu_evaluate_network, |
836 | }; | 837 | }; |
837 | 838 | ||
838 | static int fit_get_subtype(const void *fit, int noffset, char **subtype) | 839 | static int fit_get_subtype(const void *fit, int noffset, char **subtype) |
839 | { | 840 | { |
840 | int len; | 841 | int len; |
841 | 842 | ||
842 | *subtype = (char *)fdt_getprop(fit, noffset, "subtype", &len); | 843 | *subtype = (char *)fdt_getprop(fit, noffset, "subtype", &len); |
843 | if (*subtype == NULL) | 844 | if (*subtype == NULL) |
844 | return -1; | 845 | return -1; |
845 | 846 | ||
846 | return 0; | 847 | return 0; |
847 | } | 848 | } |
848 | 849 | ||
849 | static int ait_subtype_nr(char *subtype) | 850 | static int ait_subtype_nr(char *subtype) |
850 | { | 851 | { |
851 | int ret = FIT_SUBTYPE_UNKNOWN; | 852 | int ret = FIT_SUBTYPE_UNKNOWN; |
852 | 853 | ||
853 | if (!strncmp("ublheader", subtype, strlen("ublheader"))) | 854 | if (!strncmp("ublheader", subtype, strlen("ublheader"))) |
854 | return FIT_SUBTYPE_UBL_HEADER; | 855 | return FIT_SUBTYPE_UBL_HEADER; |
855 | if (!strncmp("splimage", subtype, strlen("splimage"))) | 856 | if (!strncmp("splimage", subtype, strlen("splimage"))) |
856 | return FIT_SUBTYPE_SPL_IMAGE; | 857 | return FIT_SUBTYPE_SPL_IMAGE; |
857 | if (!strncmp("ubootimage", subtype, strlen("ubootimage"))) | 858 | if (!strncmp("ubootimage", subtype, strlen("ubootimage"))) |
858 | return FIT_SUBTYPE_UBOOT_IMAGE; | 859 | return FIT_SUBTYPE_UBOOT_IMAGE; |
859 | if (!strncmp("dfenvimage", subtype, strlen("dfenvimage"))) | 860 | if (!strncmp("dfenvimage", subtype, strlen("dfenvimage"))) |
860 | return FIT_SUBTYPE_DF_ENV_IMAGE; | 861 | return FIT_SUBTYPE_DF_ENV_IMAGE; |
861 | 862 | ||
862 | return ret; | 863 | return ret; |
863 | } | 864 | } |
864 | 865 | ||
865 | static int ait_menu_check_image(void) | 866 | static int ait_menu_check_image(void) |
866 | { | 867 | { |
867 | char *s; | 868 | char *s; |
868 | unsigned long fit_addr; | 869 | unsigned long fit_addr; |
869 | void *addr; | 870 | void *addr; |
870 | int format; | 871 | int format; |
871 | char *desc; | 872 | char *desc; |
872 | char *subtype; | 873 | char *subtype; |
873 | int images_noffset; | 874 | int images_noffset; |
874 | int noffset; | 875 | int noffset; |
875 | int ndepth; | 876 | int ndepth; |
876 | int count = 0; | 877 | int count = 0; |
877 | int ret; | 878 | int ret; |
878 | int i; | 879 | int i; |
879 | int found_uboot = -1; | 880 | int found_uboot = -1; |
880 | int found_ramdisk = -1; | 881 | int found_ramdisk = -1; |
881 | 882 | ||
882 | memset(imgs, 0, sizeof(imgs)); | 883 | memset(imgs, 0, sizeof(imgs)); |
883 | s = getenv("fit_addr_r"); | 884 | s = getenv("fit_addr_r"); |
884 | fit_addr = s ? (unsigned long)simple_strtol(s, NULL, 16) : \ | 885 | fit_addr = s ? (unsigned long)simple_strtol(s, NULL, 16) : \ |
885 | CONFIG_BOARD_IMG_ADDR_R; | 886 | CONFIG_BOARD_IMG_ADDR_R; |
886 | 887 | ||
887 | addr = (void *)fit_addr; | 888 | addr = (void *)fit_addr; |
888 | /* check if it is a FIT image */ | 889 | /* check if it is a FIT image */ |
889 | format = genimg_get_format(addr); | 890 | format = genimg_get_format(addr); |
890 | if (format != IMAGE_FORMAT_FIT) | 891 | if (format != IMAGE_FORMAT_FIT) |
891 | return -EINVAL; | 892 | return -EINVAL; |
892 | 893 | ||
893 | if (!fit_check_format(addr)) | 894 | if (!fit_check_format(addr)) |
894 | return -EINVAL; | 895 | return -EINVAL; |
895 | 896 | ||
896 | /* print the FIT description */ | 897 | /* print the FIT description */ |
897 | ret = fit_get_desc(addr, 0, &desc); | 898 | ret = fit_get_desc(addr, 0, &desc); |
898 | printf("FIT description: "); | 899 | printf("FIT description: "); |
899 | if (ret) | 900 | if (ret) |
900 | printf("unavailable\n"); | 901 | printf("unavailable\n"); |
901 | else | 902 | else |
902 | printf("%s\n", desc); | 903 | printf("%s\n", desc); |
903 | 904 | ||
904 | /* find images */ | 905 | /* find images */ |
905 | images_noffset = fdt_path_offset(addr, FIT_IMAGES_PATH); | 906 | images_noffset = fdt_path_offset(addr, FIT_IMAGES_PATH); |
906 | if (images_noffset < 0) { | 907 | if (images_noffset < 0) { |
907 | printf("Can't find images parent node '%s' (%s)\n", | 908 | printf("Can't find images parent node '%s' (%s)\n", |
908 | FIT_IMAGES_PATH, fdt_strerror(images_noffset)); | 909 | FIT_IMAGES_PATH, fdt_strerror(images_noffset)); |
909 | return -EINVAL; | 910 | return -EINVAL; |
910 | } | 911 | } |
911 | 912 | ||
912 | /* Process its subnodes, print out component images details */ | 913 | /* Process its subnodes, print out component images details */ |
913 | for (ndepth = 0, count = 0, | 914 | for (ndepth = 0, count = 0, |
914 | noffset = fdt_next_node(addr, images_noffset, &ndepth); | 915 | noffset = fdt_next_node(addr, images_noffset, &ndepth); |
915 | (noffset >= 0) && (ndepth > 0); | 916 | (noffset >= 0) && (ndepth > 0); |
916 | noffset = fdt_next_node(addr, noffset, &ndepth)) { | 917 | noffset = fdt_next_node(addr, noffset, &ndepth)) { |
917 | if (ndepth == 1) { | 918 | if (ndepth == 1) { |
918 | /* | 919 | /* |
919 | * Direct child node of the images parent node, | 920 | * Direct child node of the images parent node, |
920 | * i.e. component image node. | 921 | * i.e. component image node. |
921 | */ | 922 | */ |
922 | printf("Image %u (%s)\n", count, | 923 | printf("Image %u (%s)\n", count, |
923 | fit_get_name(addr, noffset, NULL)); | 924 | fit_get_name(addr, noffset, NULL)); |
924 | 925 | ||
925 | fit_image_print(addr, noffset, ""); | 926 | fit_image_print(addr, noffset, ""); |
926 | 927 | ||
927 | fit_image_get_type(addr, noffset, | 928 | fit_image_get_type(addr, noffset, |
928 | &imgs[count].type); | 929 | &imgs[count].type); |
929 | /* Mandatory properties */ | 930 | /* Mandatory properties */ |
930 | ret = fit_get_desc(addr, noffset, &desc); | 931 | ret = fit_get_desc(addr, noffset, &desc); |
931 | printf("Description: "); | 932 | printf("Description: "); |
932 | if (ret) | 933 | if (ret) |
933 | printf("unavailable\n"); | 934 | printf("unavailable\n"); |
934 | else | 935 | else |
935 | printf("%s\n", desc); | 936 | printf("%s\n", desc); |
936 | 937 | ||
937 | ret = fit_get_subtype(addr, noffset, &subtype); | 938 | ret = fit_get_subtype(addr, noffset, &subtype); |
938 | printf("Subtype: "); | 939 | printf("Subtype: "); |
939 | if (ret) { | 940 | if (ret) { |
940 | printf("unavailable\n"); | 941 | printf("unavailable\n"); |
941 | } else { | 942 | } else { |
942 | imgs[count].subtype = ait_subtype_nr(subtype); | 943 | imgs[count].subtype = ait_subtype_nr(subtype); |
943 | printf("%s %d\n", subtype, | 944 | printf("%s %d\n", subtype, |
944 | imgs[count].subtype); | 945 | imgs[count].subtype); |
945 | } | 946 | } |
946 | 947 | ||
947 | sprintf(imgs[count].desc, "%s", desc); | 948 | sprintf(imgs[count].desc, "%s", desc); |
948 | 949 | ||
949 | ret = fit_image_get_data(addr, noffset, | 950 | ret = fit_image_get_data(addr, noffset, |
950 | &imgs[count].data, | 951 | &imgs[count].data, |
951 | &imgs[count].size); | 952 | &imgs[count].size); |
952 | 953 | ||
953 | printf("Data Size: "); | 954 | printf("Data Size: "); |
954 | if (ret) | 955 | if (ret) |
955 | printf("unavailable\n"); | 956 | printf("unavailable\n"); |
956 | else | 957 | else |
957 | genimg_print_size(imgs[count].size); | 958 | genimg_print_size(imgs[count].size); |
958 | printf("Data @ %p\n", imgs[count].data); | 959 | printf("Data @ %p\n", imgs[count].data); |
959 | count++; | 960 | count++; |
960 | } | 961 | } |
961 | } | 962 | } |
962 | 963 | ||
963 | for (i = 0; i < count; i++) { | 964 | for (i = 0; i < count; i++) { |
964 | if (imgs[i].subtype == FIT_SUBTYPE_UBOOT_IMAGE) | 965 | if (imgs[i].subtype == FIT_SUBTYPE_UBOOT_IMAGE) |
965 | found_uboot = i; | 966 | found_uboot = i; |
966 | if (imgs[i].type == IH_TYPE_RAMDISK) { | 967 | if (imgs[i].type == IH_TYPE_RAMDISK) { |
967 | found_ramdisk = i; | 968 | found_ramdisk = i; |
968 | imgs[i].subtype = FIT_SUBTYPE_RAMDISK_IMAGE; | 969 | imgs[i].subtype = FIT_SUBTYPE_RAMDISK_IMAGE; |
969 | } | 970 | } |
970 | } | 971 | } |
971 | 972 | ||
972 | /* dvn_* env var update, if the FIT descriptors are different */ | 973 | /* dvn_* env var update, if the FIT descriptors are different */ |
973 | if (found_uboot >= 0) { | 974 | if (found_uboot >= 0) { |
974 | s = getenv("dvn_boot_vers"); | 975 | s = getenv("dvn_boot_vers"); |
975 | if (s) { | 976 | if (s) { |
976 | ret = strcmp(s, imgs[found_uboot].desc); | 977 | ret = strcmp(s, imgs[found_uboot].desc); |
977 | if (ret != 0) { | 978 | if (ret != 0) { |
978 | setenv("x_dvn_boot_vers", | 979 | setenv("x_dvn_boot_vers", |
979 | imgs[found_uboot].desc); | 980 | imgs[found_uboot].desc); |
980 | } else { | 981 | } else { |
981 | found_uboot = -1; | 982 | found_uboot = -1; |
982 | printf("no new uboot version\n"); | 983 | printf("no new uboot version\n"); |
983 | } | 984 | } |
984 | } else { | 985 | } else { |
985 | setenv("dvn_boot_vers", imgs[found_uboot].desc); | 986 | setenv("dvn_boot_vers", imgs[found_uboot].desc); |
986 | } | 987 | } |
987 | } | 988 | } |
988 | if (found_ramdisk >= 0) { | 989 | if (found_ramdisk >= 0) { |
989 | s = getenv("dvn_app_vers"); | 990 | s = getenv("dvn_app_vers"); |
990 | if (s) { | 991 | if (s) { |
991 | ret = strcmp(s, imgs[found_ramdisk].desc); | 992 | ret = strcmp(s, imgs[found_ramdisk].desc); |
992 | if (ret != 0) { | 993 | if (ret != 0) { |
993 | setenv("x_dvn_app_vers", | 994 | setenv("x_dvn_app_vers", |
994 | imgs[found_ramdisk].desc); | 995 | imgs[found_ramdisk].desc); |
995 | } else { | 996 | } else { |
996 | found_ramdisk = -1; | 997 | found_ramdisk = -1; |
997 | printf("no new ramdisk version\n"); | 998 | printf("no new ramdisk version\n"); |
998 | } | 999 | } |
999 | } else { | 1000 | } else { |
1000 | setenv("dvn_app_vers", imgs[found_ramdisk].desc); | 1001 | setenv("dvn_app_vers", imgs[found_ramdisk].desc); |
1001 | } | 1002 | } |
1002 | } | 1003 | } |
1003 | if ((found_uboot == -1) && (found_ramdisk == -1)) | 1004 | if ((found_uboot == -1) && (found_ramdisk == -1)) |
1004 | return -EINVAL; | 1005 | return -EINVAL; |
1005 | 1006 | ||
1006 | return 0; | 1007 | return 0; |
1007 | } | 1008 | } |
1008 | 1009 | ||
1009 | static int ait_menu_evaluate_update(char *choice) | 1010 | static int ait_menu_evaluate_update(char *choice) |
1010 | { | 1011 | { |
1011 | int ret; | 1012 | int ret; |
1012 | 1013 | ||
1013 | if (!choice) | 1014 | if (!choice) |
1014 | return MENU_MAIN; | 1015 | return MENU_MAIN; |
1015 | 1016 | ||
1016 | switch (choice[1]) { | 1017 | switch (choice[1]) { |
1017 | case '1': | 1018 | case '1': |
1018 | return ait_menu_show(&ait_network, 0); | 1019 | return ait_menu_show(&ait_network, 0); |
1019 | break; | 1020 | break; |
1020 | case '2': | 1021 | case '2': |
1021 | /* load image */ | 1022 | /* load image */ |
1022 | ret = run_command("run load_img", 0); | 1023 | ret = run_command("run load_img", 0); |
1023 | printf("ret: %d\n", ret); | 1024 | printf("ret: %d\n", ret); |
1024 | if (ret) | 1025 | if (ret) |
1025 | return MENU_UPDATE; | 1026 | return MENU_UPDATE; |
1026 | 1027 | ||
1027 | ret = ait_menu_check_image(); | 1028 | ret = ait_menu_check_image(); |
1028 | if (ret) | 1029 | if (ret) |
1029 | return MENU_UPDATE; | 1030 | return MENU_UPDATE; |
1030 | 1031 | ||
1031 | return ait_menu_show(&ait_load, 0); | 1032 | return ait_menu_show(&ait_load, 0); |
1032 | break; | 1033 | break; |
1033 | case '3': | 1034 | case '3': |
1034 | return MENU_MAIN; | 1035 | return MENU_MAIN; |
1035 | break; | 1036 | break; |
1036 | 1037 | ||
1037 | } | 1038 | } |
1038 | 1039 | ||
1039 | return MENU_MAIN; | 1040 | return MENU_MAIN; |
1040 | } | 1041 | } |
1041 | 1042 | ||
1042 | struct menu_display ait_update = { | 1043 | struct menu_display ait_update = { |
1043 | .title = "AIT Update Software", | 1044 | .title = "AIT Update Software", |
1044 | .timeout = 0, | 1045 | .timeout = 0, |
1045 | .id = MENU_UPDATE, | 1046 | .id = MENU_UPDATE, |
1046 | .menulist = menu_update, | 1047 | .menulist = menu_update, |
1047 | .menu_evaluate = ait_menu_evaluate_update, | 1048 | .menu_evaluate = ait_menu_evaluate_update, |
1048 | }; | 1049 | }; |
1049 | 1050 | ||
1050 | static int ait_menu_evaluate_main(char *choice) | 1051 | static int ait_menu_evaluate_main(char *choice) |
1051 | { | 1052 | { |
1052 | if (!choice) | 1053 | if (!choice) |
1053 | return MENU_STAY; | 1054 | return MENU_STAY; |
1054 | 1055 | ||
1055 | menu_start = 1; | 1056 | menu_start = 1; |
1056 | switch (choice[1]) { | 1057 | switch (choice[1]) { |
1057 | case '1': | 1058 | case '1': |
1058 | /* run bootcmd */ | 1059 | /* run bootcmd */ |
1059 | return MENU_EXIT_BOOTCMD; | 1060 | return MENU_EXIT_BOOTCMD; |
1060 | break; | 1061 | break; |
1061 | case '2': | 1062 | case '2': |
1062 | return ait_menu_show(&ait_update, 0); | 1063 | return ait_menu_show(&ait_update, 0); |
1063 | break; | 1064 | break; |
1064 | case '3': | 1065 | case '3': |
1065 | /* reset to default settings */ | 1066 | /* reset to default settings */ |
1066 | setenv("app_reset", "yes"); | 1067 | setenv("app_reset", "yes"); |
1067 | return MENU_EXIT_BOOTCMD; | 1068 | return MENU_EXIT_BOOTCMD; |
1068 | break; | 1069 | break; |
1069 | case '4': | 1070 | case '4': |
1070 | /* u-boot shell */ | 1071 | /* u-boot shell */ |
1071 | return MENU_EXIT; | 1072 | return MENU_EXIT; |
1072 | break; | 1073 | break; |
1073 | } | 1074 | } |
1074 | 1075 | ||
1075 | return MENU_EXIT; | 1076 | return MENU_EXIT; |
1076 | } | 1077 | } |
1077 | 1078 | ||
1078 | struct menu_display ait_main = { | 1079 | struct menu_display ait_main = { |
1079 | .title = "AIT Main", | 1080 | .title = "AIT Main", |
1080 | .timeout = CONFIG_BOOTDELAY, | 1081 | .timeout = CONFIG_BOOTDELAY, |
1081 | .id = MENU_MAIN, | 1082 | .id = MENU_MAIN, |
1082 | .menulist = menu_main, | 1083 | .menulist = menu_main, |
1083 | .menu_evaluate = ait_menu_evaluate_main, | 1084 | .menu_evaluate = ait_menu_evaluate_main, |
1084 | }; | 1085 | }; |
1085 | 1086 | ||
1086 | int menu_show(int bootdelay) | 1087 | int menu_show(int bootdelay) |
1087 | { | 1088 | { |
1088 | int ret; | 1089 | int ret; |
1089 | 1090 | ||
1090 | run_command("run saveparms", 0); | 1091 | run_command("run saveparms", 0); |
1091 | ret = ait_menu_show(&ait_main, bootdelay); | 1092 | ret = ait_menu_show(&ait_main, bootdelay); |
1092 | run_command("run restoreparms", 0); | 1093 | run_command("run restoreparms", 0); |
1093 | 1094 | ||
1094 | if (ret == MENU_EXIT_BOOTCMD) | 1095 | if (ret == MENU_EXIT_BOOTCMD) |
1095 | return 0; | 1096 | return 0; |
1096 | 1097 | ||
1097 | return MENU_EXIT; | 1098 | return MENU_EXIT; |
1098 | } | 1099 | } |
1099 | 1100 | ||
1100 | void menu_display_statusline(struct menu *m) | 1101 | void menu_display_statusline(struct menu *m) |
1101 | { | 1102 | { |
1102 | char *s1, *s2; | 1103 | char *s1, *s2; |
1103 | 1104 | ||
1104 | s1 = getenv("x_dvn_boot_vers"); | 1105 | s1 = getenv("x_dvn_boot_vers"); |
1105 | if (!s1) | 1106 | if (!s1) |
1106 | s1 = getenv("dvn_boot_vers"); | 1107 | s1 = getenv("dvn_boot_vers"); |
1107 | 1108 | ||
1108 | s2 = getenv("x_dvn_app_vers"); | 1109 | s2 = getenv("x_dvn_app_vers"); |
1109 | if (!s2) | 1110 | if (!s2) |
1110 | s2 = getenv("dvn_app_vers"); | 1111 | s2 = getenv("dvn_app_vers"); |
1111 | 1112 | ||
1112 | printf("State: dvn_boot_vers: %s dvn_app_vers: %s\n", s1, s2); | 1113 | printf("State: dvn_boot_vers: %s dvn_app_vers: %s\n", s1, s2); |
1113 | return; | 1114 | return; |
1114 | } | 1115 | } |
1115 | #endif | 1116 | #endif |
1116 | 1117 |
common/Makefile
1 | # | 1 | # |
2 | # (C) Copyright 2004-2006 | 2 | # (C) Copyright 2004-2006 |
3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
4 | # | 4 | # |
5 | # See file CREDITS for list of people who contributed to this | 5 | # See file CREDITS for list of people who contributed to this |
6 | # project. | 6 | # project. |
7 | # | 7 | # |
8 | # This program is free software; you can redistribute it and/or | 8 | # This program is free software; you can redistribute it and/or |
9 | # modify it under the terms of the GNU General Public License as | 9 | # modify it under the terms of the GNU General Public License as |
10 | # published by the Free Software Foundation; either version 2 of | 10 | # published by the Free Software Foundation; either version 2 of |
11 | # the License, or (at your option) any later version. | 11 | # the License, or (at your option) any later version. |
12 | # | 12 | # |
13 | # This program is distributed in the hope that it will be useful, | 13 | # This program is distributed in the hope that it will be useful, |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | # GNU General Public License for more details. | 16 | # GNU General Public License for more details. |
17 | # | 17 | # |
18 | # You should have received a copy of the GNU General Public License | 18 | # You should have received a copy of the GNU General Public License |
19 | # along with this program; if not, write to the Free Software | 19 | # along with this program; if not, write to the Free Software |
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
21 | # MA 02111-1307 USA | 21 | # MA 02111-1307 USA |
22 | # | 22 | # |
23 | 23 | ||
24 | include $(TOPDIR)/config.mk | 24 | include $(TOPDIR)/config.mk |
25 | 25 | ||
26 | LIB = $(obj)libcommon.o | 26 | LIB = $(obj)libcommon.o |
27 | 27 | ||
28 | # core | 28 | # core |
29 | ifndef CONFIG_SPL_BUILD | 29 | ifndef CONFIG_SPL_BUILD |
30 | COBJS-y += main.o | 30 | COBJS-y += main.o |
31 | COBJS-y += command.o | 31 | COBJS-y += command.o |
32 | COBJS-y += exports.o | 32 | COBJS-y += exports.o |
33 | COBJS-y += hash.o | 33 | COBJS-y += hash.o |
34 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o | 34 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o |
35 | COBJS-y += s_record.o | 35 | COBJS-y += s_record.o |
36 | COBJS-y += xyzModem.o | 36 | COBJS-y += xyzModem.o |
37 | COBJS-y += cmd_disk.o | 37 | COBJS-y += cmd_disk.o |
38 | 38 | ||
39 | # boards | 39 | # boards |
40 | COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_f.o | 40 | COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_f.o |
41 | COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o | 41 | COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o |
42 | 42 | ||
43 | # core command | 43 | # core command |
44 | COBJS-y += cmd_boot.o | 44 | COBJS-y += cmd_boot.o |
45 | COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o | 45 | COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o |
46 | COBJS-y += cmd_help.o | 46 | COBJS-y += cmd_help.o |
47 | COBJS-y += cmd_nvedit.o | 47 | COBJS-y += cmd_nvedit.o |
48 | COBJS-y += cmd_version.o | 48 | COBJS-y += cmd_version.o |
49 | 49 | ||
50 | # environment | 50 | # environment |
51 | COBJS-y += env_attr.o | 51 | COBJS-y += env_attr.o |
52 | COBJS-y += env_callback.o | 52 | COBJS-y += env_callback.o |
53 | COBJS-y += env_common.o | 53 | COBJS-y += env_common.o |
54 | COBJS-y += env_flags.o | 54 | COBJS-y += env_flags.o |
55 | COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o | 55 | COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o |
56 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o | 56 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o |
57 | XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o | 57 | XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o |
58 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_embedded.o | 58 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_embedded.o |
59 | XCOBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_embedded.o | 59 | XCOBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_embedded.o |
60 | COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_embedded.o | 60 | COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_embedded.o |
61 | COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o | 61 | COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o |
62 | COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o | 62 | COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o |
63 | COBJS-$(CONFIG_ENV_IS_IN_FAT) += env_fat.o | 63 | COBJS-$(CONFIG_ENV_IS_IN_FAT) += env_fat.o |
64 | COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o | 64 | COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o |
65 | COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o | 65 | COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o |
66 | COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o | 66 | COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o |
67 | COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o | 67 | COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o |
68 | COBJS-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o | 68 | COBJS-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o |
69 | COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o | 69 | COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o |
70 | 70 | ||
71 | # command | 71 | # command |
72 | COBJS-$(CONFIG_CMD_AMBAPP) += cmd_ambapp.o | 72 | COBJS-$(CONFIG_CMD_AMBAPP) += cmd_ambapp.o |
73 | COBJS-$(CONFIG_SOURCE) += cmd_source.o | 73 | COBJS-$(CONFIG_SOURCE) += cmd_source.o |
74 | COBJS-$(CONFIG_CMD_SOURCE) += cmd_source.o | 74 | COBJS-$(CONFIG_CMD_SOURCE) += cmd_source.o |
75 | COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o | 75 | COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o |
76 | COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o | 76 | COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o |
77 | COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o | 77 | COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o |
78 | COBJS-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o | ||
78 | COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o | 79 | COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o |
79 | COBJS-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o | 80 | COBJS-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o |
80 | COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o | 81 | COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o |
81 | COBJS-$(CONFIG_CMD_CBFS) += cmd_cbfs.o | 82 | COBJS-$(CONFIG_CMD_CBFS) += cmd_cbfs.o |
82 | COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o | 83 | COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o |
83 | COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o | 84 | COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o |
84 | COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o | 85 | COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o |
85 | COBJS-$(CONFIG_CMD_DATE) += cmd_date.o | 86 | COBJS-$(CONFIG_CMD_DATE) += cmd_date.o |
86 | COBJS-$(CONFIG_CMD_SOUND) += cmd_sound.o | 87 | COBJS-$(CONFIG_CMD_SOUND) += cmd_sound.o |
87 | ifdef CONFIG_4xx | 88 | ifdef CONFIG_4xx |
88 | COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o | 89 | COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o |
89 | endif | 90 | endif |
90 | ifdef CONFIG_POST | 91 | ifdef CONFIG_POST |
91 | COBJS-$(CONFIG_CMD_DIAG) += cmd_diag.o | 92 | COBJS-$(CONFIG_CMD_DIAG) += cmd_diag.o |
92 | endif | 93 | endif |
93 | COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o | 94 | COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o |
94 | COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o | 95 | COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o |
95 | COBJS-$(CONFIG_CMD_ECHO) += cmd_echo.o | 96 | COBJS-$(CONFIG_CMD_ECHO) += cmd_echo.o |
96 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o | 97 | COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o |
97 | COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o | 98 | COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o |
98 | COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o | 99 | COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o |
99 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o | 100 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o |
100 | COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o | 101 | COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o |
101 | COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o | 102 | COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o |
102 | COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o | 103 | COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o |
103 | COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o | 104 | COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o |
104 | COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o | 105 | COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o |
105 | COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o | 106 | COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o |
106 | COBJS-$(CONFIG_CMD_FITUPD) += cmd_fitupd.o | 107 | COBJS-$(CONFIG_CMD_FITUPD) += cmd_fitupd.o |
107 | COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o | 108 | COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o |
108 | ifdef CONFIG_FPGA | 109 | ifdef CONFIG_FPGA |
109 | COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o | 110 | COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o |
110 | endif | 111 | endif |
111 | COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o | 112 | COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o |
112 | COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o | 113 | COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o |
113 | COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o | 114 | COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o |
114 | COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o | 115 | COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o |
115 | COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o | 116 | COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o |
116 | COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o | 117 | COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o |
117 | COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o | 118 | COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o |
118 | COBJS-$(CONFIG_CMD_INI) += cmd_ini.o | 119 | COBJS-$(CONFIG_CMD_INI) += cmd_ini.o |
119 | COBJS-$(CONFIG_CMD_IRQ) += cmd_irq.o | 120 | COBJS-$(CONFIG_CMD_IRQ) += cmd_irq.o |
120 | COBJS-$(CONFIG_CMD_ITEST) += cmd_itest.o | 121 | COBJS-$(CONFIG_CMD_ITEST) += cmd_itest.o |
121 | COBJS-$(CONFIG_CMD_JFFS2) += cmd_jffs2.o | 122 | COBJS-$(CONFIG_CMD_JFFS2) += cmd_jffs2.o |
122 | COBJS-$(CONFIG_CMD_CRAMFS) += cmd_cramfs.o | 123 | COBJS-$(CONFIG_CMD_CRAMFS) += cmd_cramfs.o |
123 | COBJS-$(CONFIG_CMD_LDRINFO) += cmd_ldrinfo.o | 124 | COBJS-$(CONFIG_CMD_LDRINFO) += cmd_ldrinfo.o |
124 | COBJS-$(CONFIG_CMD_LED) += cmd_led.o | 125 | COBJS-$(CONFIG_CMD_LED) += cmd_led.o |
125 | COBJS-$(CONFIG_CMD_LICENSE) += cmd_license.o | 126 | COBJS-$(CONFIG_CMD_LICENSE) += cmd_license.o |
126 | COBJS-y += cmd_load.o | 127 | COBJS-y += cmd_load.o |
127 | COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o | 128 | COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o |
128 | COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o | 129 | COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o |
129 | COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o | 130 | COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o |
130 | COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o | 131 | COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o |
131 | COBJS-$(CONFIG_CMD_IO) += cmd_io.o | 132 | COBJS-$(CONFIG_CMD_IO) += cmd_io.o |
132 | COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o | 133 | COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o |
133 | COBJS-$(CONFIG_MII) += miiphyutil.o | 134 | COBJS-$(CONFIG_MII) += miiphyutil.o |
134 | COBJS-$(CONFIG_CMD_MII) += miiphyutil.o | 135 | COBJS-$(CONFIG_CMD_MII) += miiphyutil.o |
135 | COBJS-$(CONFIG_PHYLIB) += miiphyutil.o | 136 | COBJS-$(CONFIG_PHYLIB) += miiphyutil.o |
136 | COBJS-$(CONFIG_CMD_MII) += cmd_mii.o | 137 | COBJS-$(CONFIG_CMD_MII) += cmd_mii.o |
137 | ifdef CONFIG_PHYLIB | 138 | ifdef CONFIG_PHYLIB |
138 | COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o | 139 | COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o |
139 | endif | 140 | endif |
140 | COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o | 141 | COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o |
141 | COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o | 142 | COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o |
142 | COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o | 143 | COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o |
143 | COBJS-$(CONFIG_MP) += cmd_mp.o | 144 | COBJS-$(CONFIG_MP) += cmd_mp.o |
144 | COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o | 145 | COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o |
145 | COBJS-$(CONFIG_CMD_NAND) += cmd_nand.o | 146 | COBJS-$(CONFIG_CMD_NAND) += cmd_nand.o |
146 | COBJS-$(CONFIG_CMD_NET) += cmd_net.o | 147 | COBJS-$(CONFIG_CMD_NET) += cmd_net.o |
147 | COBJS-$(CONFIG_CMD_ONENAND) += cmd_onenand.o | 148 | COBJS-$(CONFIG_CMD_ONENAND) += cmd_onenand.o |
148 | COBJS-$(CONFIG_CMD_OTP) += cmd_otp.o | 149 | COBJS-$(CONFIG_CMD_OTP) += cmd_otp.o |
149 | COBJS-$(CONFIG_CMD_PART) += cmd_part.o | 150 | COBJS-$(CONFIG_CMD_PART) += cmd_part.o |
150 | ifdef CONFIG_PCI | 151 | ifdef CONFIG_PCI |
151 | COBJS-$(CONFIG_CMD_PCI) += cmd_pci.o | 152 | COBJS-$(CONFIG_CMD_PCI) += cmd_pci.o |
152 | endif | 153 | endif |
153 | COBJS-y += cmd_pcmcia.o | 154 | COBJS-y += cmd_pcmcia.o |
154 | COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o | 155 | COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o |
155 | COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o | 156 | COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o |
156 | COBJS-$(CONFIG_CMD_READ) += cmd_read.o | 157 | COBJS-$(CONFIG_CMD_READ) += cmd_read.o |
157 | COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o | 158 | COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o |
158 | COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o | 159 | COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o |
159 | COBJS-$(CONFIG_SANDBOX) += cmd_sandbox.o | 160 | COBJS-$(CONFIG_SANDBOX) += cmd_sandbox.o |
160 | COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o | 161 | COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o |
161 | COBJS-$(CONFIG_CMD_SF) += cmd_sf.o | 162 | COBJS-$(CONFIG_CMD_SF) += cmd_sf.o |
162 | COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o | 163 | COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o |
163 | COBJS-$(CONFIG_CMD_SHA1SUM) += cmd_sha1sum.o | 164 | COBJS-$(CONFIG_CMD_SHA1SUM) += cmd_sha1sum.o |
164 | COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o | 165 | COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o |
165 | COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o | 166 | COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o |
166 | COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o | 167 | COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o |
167 | COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o | 168 | COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o |
168 | COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o | 169 | COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o |
169 | COBJS-$(CONFIG_CMD_TIME) += cmd_time.o | 170 | COBJS-$(CONFIG_CMD_TIME) += cmd_time.o |
170 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o | 171 | COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o |
171 | COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o | 172 | COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o |
172 | COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o | 173 | COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o |
173 | COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o | 174 | COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o |
174 | COBJS-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o | 175 | COBJS-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o |
175 | COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o | 176 | COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o |
176 | COBJS-$(CONFIG_CMD_UNZIP) += cmd_unzip.o | 177 | COBJS-$(CONFIG_CMD_UNZIP) += cmd_unzip.o |
177 | ifdef CONFIG_CMD_USB | 178 | ifdef CONFIG_CMD_USB |
178 | COBJS-y += cmd_usb.o | 179 | COBJS-y += cmd_usb.o |
179 | COBJS-y += usb.o usb_hub.o | 180 | COBJS-y += usb.o usb_hub.o |
180 | COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o | 181 | COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o |
181 | endif | 182 | endif |
182 | COBJS-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o | 183 | COBJS-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o |
183 | COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o | 184 | COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o |
184 | COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o | 185 | COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o |
185 | COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o | 186 | COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o |
186 | COBJS-$(CONFIG_CMD_ZIP) += cmd_zip.o | 187 | COBJS-$(CONFIG_CMD_ZIP) += cmd_zip.o |
187 | COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o | 188 | COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o |
188 | 189 | ||
189 | # others | 190 | # others |
190 | ifdef CONFIG_DDR_SPD | 191 | ifdef CONFIG_DDR_SPD |
191 | SPD := y | 192 | SPD := y |
192 | endif | 193 | endif |
193 | ifdef CONFIG_SPD_EEPROM | 194 | ifdef CONFIG_SPD_EEPROM |
194 | SPD := y | 195 | SPD := y |
195 | endif | 196 | endif |
196 | COBJS-$(SPD) += ddr_spd.o | 197 | COBJS-$(SPD) += ddr_spd.o |
197 | COBJS-$(CONFIG_HWCONFIG) += hwconfig.o | 198 | COBJS-$(CONFIG_HWCONFIG) += hwconfig.o |
198 | COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o | 199 | COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o |
199 | COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o | 200 | COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o |
200 | COBJS-y += flash.o | 201 | COBJS-y += flash.o |
201 | COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o | 202 | COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o |
202 | COBJS-$(CONFIG_I2C_EDID) += edid.o | 203 | COBJS-$(CONFIG_I2C_EDID) += edid.o |
203 | COBJS-$(CONFIG_KALLSYMS) += kallsyms.o | 204 | COBJS-$(CONFIG_KALLSYMS) += kallsyms.o |
204 | COBJS-$(CONFIG_LCD) += lcd.o | 205 | COBJS-$(CONFIG_LCD) += lcd.o |
205 | COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o | 206 | COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o |
206 | COBJS-$(CONFIG_MENU) += menu.o | 207 | COBJS-$(CONFIG_MENU) += menu.o |
207 | COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o | 208 | COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o |
208 | COBJS-$(CONFIG_UPDATE_TFTP) += update.o | 209 | COBJS-$(CONFIG_UPDATE_TFTP) += update.o |
209 | COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o | 210 | COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o |
210 | COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o | 211 | COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o |
211 | COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o | 212 | COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o |
212 | endif | 213 | endif |
213 | 214 | ||
214 | ifdef CONFIG_SPL_BUILD | 215 | ifdef CONFIG_SPL_BUILD |
215 | COBJS-y += cmd_nvedit.o | 216 | COBJS-y += cmd_nvedit.o |
216 | COBJS-y += env_common.o | 217 | COBJS-y += env_common.o |
217 | COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o | 218 | COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o |
218 | COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o | 219 | COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o |
219 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o | 220 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o |
220 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o | 221 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o |
221 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o | 222 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o |
222 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o | 223 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o |
223 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o | 224 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o |
224 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o | 225 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o |
225 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o | 226 | COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o |
226 | endif | 227 | endif |
227 | COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o | 228 | COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o |
228 | COBJS-y += console.o | 229 | COBJS-y += console.o |
229 | COBJS-y += dlmalloc.o | 230 | COBJS-y += dlmalloc.o |
230 | COBJS-y += image.o | 231 | COBJS-y += image.o |
231 | COBJS-y += memsize.o | 232 | COBJS-y += memsize.o |
232 | COBJS-y += stdio.o | 233 | COBJS-y += stdio.o |
233 | 234 | ||
234 | 235 | ||
235 | COBJS := $(sort $(COBJS-y)) | 236 | COBJS := $(sort $(COBJS-y)) |
236 | XCOBJS := $(sort $(XCOBJS-y)) | 237 | XCOBJS := $(sort $(XCOBJS-y)) |
237 | SRCS := $(COBJS:.o=.c) $(XCOBJS:.o=.c) | 238 | SRCS := $(COBJS:.o=.c) $(XCOBJS:.o=.c) |
238 | OBJS := $(addprefix $(obj),$(COBJS)) | 239 | OBJS := $(addprefix $(obj),$(COBJS)) |
239 | XOBJS := $(addprefix $(obj),$(XCOBJS)) | 240 | XOBJS := $(addprefix $(obj),$(XCOBJS)) |
240 | 241 | ||
241 | CPPFLAGS += -I.. | 242 | CPPFLAGS += -I.. |
242 | 243 | ||
243 | all: $(LIB) $(XOBJS) | 244 | all: $(LIB) $(XOBJS) |
244 | 245 | ||
245 | $(LIB): $(obj).depend $(OBJS) | 246 | $(LIB): $(obj).depend $(OBJS) |
246 | $(call cmd_link_o_target, $(OBJS)) | 247 | $(call cmd_link_o_target, $(OBJS)) |
247 | 248 | ||
248 | $(obj)env_embedded.o: $(src)env_embedded.c $(obj)../tools/envcrc | 249 | $(obj)env_embedded.o: $(src)env_embedded.c $(obj)../tools/envcrc |
249 | $(CC) $(AFLAGS) -Wa,--no-warn \ | 250 | $(CC) $(AFLAGS) -Wa,--no-warn \ |
250 | -DENV_CRC=$(shell $(obj)../tools/envcrc) \ | 251 | -DENV_CRC=$(shell $(obj)../tools/envcrc) \ |
251 | -c -o $@ $(src)env_embedded.c | 252 | -c -o $@ $(src)env_embedded.c |
252 | 253 | ||
253 | $(obj)../tools/envcrc: | 254 | $(obj)../tools/envcrc: |
254 | $(MAKE) -C ../tools | 255 | $(MAKE) -C ../tools |
255 | 256 | ||
256 | # SEE README.arm-unaligned-accesses | 257 | # SEE README.arm-unaligned-accesses |
257 | $(obj)hush.o: CFLAGS += $(PLATFORM_NO_UNALIGNED) | 258 | $(obj)hush.o: CFLAGS += $(PLATFORM_NO_UNALIGNED) |
258 | $(obj)fdt_support.o: CFLAGS += $(PLATFORM_NO_UNALIGNED) | 259 | $(obj)fdt_support.o: CFLAGS += $(PLATFORM_NO_UNALIGNED) |
259 | 260 | ||
260 | ######################################################################### | 261 | ######################################################################### |
261 | 262 | ||
262 | # defines $(obj).depend target | 263 | # defines $(obj).depend target |
263 | include $(SRCTREE)/rules.mk | 264 | include $(SRCTREE)/rules.mk |
264 | 265 | ||
265 | sinclude $(obj).depend | 266 | sinclude $(obj).depend |
266 | 267 | ||
267 | ######################################################################### | 268 | ######################################################################### |
268 | 269 |
common/cmd_bootmenu.c
File was created | 1 | /* | |
2 | * (C) Copyright 2011-2013 Pali Rohรกr <pali.rohar@gmail.com> | ||
3 | * | ||
4 | * See file CREDITS for list of people who contributed to this | ||
5 | * project. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
20 | * MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <common.h> | ||
24 | #include <command.h> | ||
25 | #include <ansi.h> | ||
26 | #include <menu.h> | ||
27 | #include <hush.h> | ||
28 | #include <watchdog.h> | ||
29 | #include <malloc.h> | ||
30 | #include <linux/string.h> | ||
31 | |||
32 | /* maximum bootmenu entries */ | ||
33 | #define MAX_COUNT 99 | ||
34 | |||
35 | /* maximal size of bootmenu env | ||
36 | * 9 = strlen("bootmenu_") | ||
37 | * 2 = strlen(MAX_COUNT) | ||
38 | * 1 = NULL term | ||
39 | */ | ||
40 | #define MAX_ENV_SIZE (9 + 2 + 1) | ||
41 | |||
42 | struct bootmenu_entry { | ||
43 | unsigned short int num; /* unique number 0 .. MAX_COUNT */ | ||
44 | char key[3]; /* key identifier of number */ | ||
45 | char *title; /* title of entry */ | ||
46 | char *command; /* hush command of entry */ | ||
47 | struct bootmenu_data *menu; /* this bootmenu */ | ||
48 | struct bootmenu_entry *next; /* next menu entry (num+1) */ | ||
49 | }; | ||
50 | |||
51 | struct bootmenu_data { | ||
52 | int delay; /* delay for autoboot */ | ||
53 | int active; /* active menu entry */ | ||
54 | int count; /* total count of menu entries */ | ||
55 | struct bootmenu_entry *first; /* first menu entry */ | ||
56 | }; | ||
57 | |||
58 | enum bootmenu_key { | ||
59 | KEY_NONE = 0, | ||
60 | KEY_UP, | ||
61 | KEY_DOWN, | ||
62 | KEY_SELECT, | ||
63 | }; | ||
64 | |||
65 | static char *bootmenu_getoption(unsigned short int n) | ||
66 | { | ||
67 | char name[MAX_ENV_SIZE] = "bootmenu_"; | ||
68 | |||
69 | if (n > MAX_COUNT) | ||
70 | return NULL; | ||
71 | |||
72 | sprintf(name + 9, "%d", n); | ||
73 | return getenv(name); | ||
74 | } | ||
75 | |||
76 | static void bootmenu_print_entry(void *data) | ||
77 | { | ||
78 | struct bootmenu_entry *entry = data; | ||
79 | int reverse = (entry->menu->active == entry->num); | ||
80 | |||
81 | /* | ||
82 | * Move cursor to line where the entry will be drown (entry->num) | ||
83 | * First 3 lines contain bootmenu header + 1 empty line | ||
84 | */ | ||
85 | printf(ANSI_CURSOR_POSITION, entry->num + 4, 1); | ||
86 | |||
87 | puts(" "); | ||
88 | |||
89 | if (reverse) | ||
90 | puts(ANSI_COLOR_REVERSE); | ||
91 | |||
92 | puts(entry->title); | ||
93 | |||
94 | if (reverse) | ||
95 | puts(ANSI_COLOR_RESET); | ||
96 | } | ||
97 | |||
98 | static void bootmenu_autoboot_loop(struct bootmenu_data *menu, | ||
99 | enum bootmenu_key *key, int *esc) | ||
100 | { | ||
101 | int i, c; | ||
102 | |||
103 | if (menu->delay > 0) { | ||
104 | printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | ||
105 | printf(" Hit any key to stop autoboot: %2d ", menu->delay); | ||
106 | } | ||
107 | |||
108 | while (menu->delay > 0) { | ||
109 | for (i = 0; i < 100; ++i) { | ||
110 | if (!tstc()) { | ||
111 | WATCHDOG_RESET(); | ||
112 | mdelay(10); | ||
113 | continue; | ||
114 | } | ||
115 | |||
116 | menu->delay = -1; | ||
117 | c = getc(); | ||
118 | |||
119 | switch (c) { | ||
120 | case '\e': | ||
121 | *esc = 1; | ||
122 | *key = KEY_NONE; | ||
123 | break; | ||
124 | case '\r': | ||
125 | *key = KEY_SELECT; | ||
126 | break; | ||
127 | default: | ||
128 | *key = KEY_NONE; | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | break; | ||
133 | } | ||
134 | |||
135 | if (menu->delay < 0) | ||
136 | break; | ||
137 | |||
138 | --menu->delay; | ||
139 | printf("\b\b\b%2d ", menu->delay); | ||
140 | } | ||
141 | |||
142 | printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | ||
143 | puts(ANSI_CLEAR_LINE); | ||
144 | |||
145 | if (menu->delay == 0) | ||
146 | *key = KEY_SELECT; | ||
147 | } | ||
148 | |||
149 | static void bootmenu_loop(struct bootmenu_data *menu, | ||
150 | enum bootmenu_key *key, int *esc) | ||
151 | { | ||
152 | int c; | ||
153 | |||
154 | while (!tstc()) { | ||
155 | WATCHDOG_RESET(); | ||
156 | mdelay(10); | ||
157 | } | ||
158 | |||
159 | c = getc(); | ||
160 | |||
161 | switch (*esc) { | ||
162 | case 0: | ||
163 | /* First char of ANSI escape sequence '\e' */ | ||
164 | if (c == '\e') { | ||
165 | *esc = 1; | ||
166 | *key = KEY_NONE; | ||
167 | } | ||
168 | break; | ||
169 | case 1: | ||
170 | /* Second char of ANSI '[' */ | ||
171 | if (c == '[') { | ||
172 | *esc = 2; | ||
173 | *key = KEY_NONE; | ||
174 | } else { | ||
175 | *esc = 0; | ||
176 | } | ||
177 | break; | ||
178 | case 2: | ||
179 | case 3: | ||
180 | /* Third char of ANSI (number '1') - optional */ | ||
181 | if (*esc == 2 && c == '1') { | ||
182 | *esc = 3; | ||
183 | *key = KEY_NONE; | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | *esc = 0; | ||
188 | |||
189 | /* ANSI 'A' - key up was pressed */ | ||
190 | if (c == 'A') | ||
191 | *key = KEY_UP; | ||
192 | /* ANSI 'B' - key down was pressed */ | ||
193 | else if (c == 'B') | ||
194 | *key = KEY_DOWN; | ||
195 | /* other key was pressed */ | ||
196 | else | ||
197 | *key = KEY_NONE; | ||
198 | |||
199 | break; | ||
200 | } | ||
201 | |||
202 | /* enter key was pressed */ | ||
203 | if (c == '\r') | ||
204 | *key = KEY_SELECT; | ||
205 | } | ||
206 | |||
207 | static char *bootmenu_choice_entry(void *data) | ||
208 | { | ||
209 | struct bootmenu_data *menu = data; | ||
210 | struct bootmenu_entry *iter; | ||
211 | enum bootmenu_key key = KEY_NONE; | ||
212 | int esc = 0; | ||
213 | int i; | ||
214 | |||
215 | while (1) { | ||
216 | if (menu->delay >= 0) { | ||
217 | /* Autoboot was not stopped */ | ||
218 | bootmenu_autoboot_loop(menu, &key, &esc); | ||
219 | } else { | ||
220 | /* Some key was pressed, so autoboot was stopped */ | ||
221 | bootmenu_loop(menu, &key, &esc); | ||
222 | } | ||
223 | |||
224 | switch (key) { | ||
225 | case KEY_UP: | ||
226 | if (menu->active > 0) | ||
227 | --menu->active; | ||
228 | /* no menu key selected, regenerate menu */ | ||
229 | return NULL; | ||
230 | case KEY_DOWN: | ||
231 | if (menu->active < menu->count - 1) | ||
232 | ++menu->active; | ||
233 | /* no menu key selected, regenerate menu */ | ||
234 | return NULL; | ||
235 | case KEY_SELECT: | ||
236 | iter = menu->first; | ||
237 | for (i = 0; i < menu->active; ++i) | ||
238 | iter = iter->next; | ||
239 | return iter->key; | ||
240 | default: | ||
241 | break; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* never happens */ | ||
246 | debug("bootmenu: this should not happen"); | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | static void bootmenu_destroy(struct bootmenu_data *menu) | ||
251 | { | ||
252 | struct bootmenu_entry *iter = menu->first; | ||
253 | struct bootmenu_entry *next; | ||
254 | |||
255 | while (iter) { | ||
256 | next = iter->next; | ||
257 | free(iter->title); | ||
258 | free(iter->command); | ||
259 | free(iter); | ||
260 | iter = next; | ||
261 | } | ||
262 | free(menu); | ||
263 | } | ||
264 | |||
265 | static struct bootmenu_data *bootmenu_create(int delay) | ||
266 | { | ||
267 | unsigned short int i = 0; | ||
268 | const char *option; | ||
269 | struct bootmenu_data *menu; | ||
270 | struct bootmenu_entry *iter = NULL; | ||
271 | |||
272 | int len; | ||
273 | char *sep; | ||
274 | struct bootmenu_entry *entry; | ||
275 | |||
276 | menu = malloc(sizeof(struct bootmenu_data)); | ||
277 | if (!menu) | ||
278 | return NULL; | ||
279 | |||
280 | menu->delay = delay; | ||
281 | menu->active = 0; | ||
282 | menu->first = NULL; | ||
283 | |||
284 | while ((option = bootmenu_getoption(i))) { | ||
285 | sep = strchr(option, '='); | ||
286 | if (!sep) { | ||
287 | printf("Invalid bootmenu entry: %s\n", option); | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | entry = malloc(sizeof(struct bootmenu_entry)); | ||
292 | if (!entry) | ||
293 | goto cleanup; | ||
294 | |||
295 | len = sep-option; | ||
296 | entry->title = malloc(len + 1); | ||
297 | if (!entry->title) { | ||
298 | free(entry); | ||
299 | goto cleanup; | ||
300 | } | ||
301 | memcpy(entry->title, option, len); | ||
302 | entry->title[len] = 0; | ||
303 | |||
304 | len = strlen(sep + 1); | ||
305 | entry->command = malloc(len + 1); | ||
306 | if (!entry->command) { | ||
307 | free(entry->title); | ||
308 | free(entry); | ||
309 | goto cleanup; | ||
310 | } | ||
311 | memcpy(entry->command, sep + 1, len); | ||
312 | entry->command[len] = 0; | ||
313 | |||
314 | sprintf(entry->key, "%d", i); | ||
315 | |||
316 | entry->num = i; | ||
317 | entry->menu = menu; | ||
318 | entry->next = NULL; | ||
319 | |||
320 | if (!iter) | ||
321 | menu->first = entry; | ||
322 | else | ||
323 | iter->next = entry; | ||
324 | |||
325 | iter = entry; | ||
326 | ++i; | ||
327 | |||
328 | if (i == MAX_COUNT - 1) | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | /* Add U-Boot console entry at the end */ | ||
333 | if (i <= MAX_COUNT - 1) { | ||
334 | entry = malloc(sizeof(struct bootmenu_entry)); | ||
335 | if (!entry) | ||
336 | goto cleanup; | ||
337 | |||
338 | entry->title = strdup("U-Boot console"); | ||
339 | if (!entry->title) { | ||
340 | free(entry); | ||
341 | goto cleanup; | ||
342 | } | ||
343 | |||
344 | entry->command = strdup(""); | ||
345 | if (!entry->command) { | ||
346 | free(entry->title); | ||
347 | free(entry); | ||
348 | goto cleanup; | ||
349 | } | ||
350 | |||
351 | sprintf(entry->key, "%d", i); | ||
352 | |||
353 | entry->num = i; | ||
354 | entry->menu = menu; | ||
355 | entry->next = NULL; | ||
356 | |||
357 | if (!iter) | ||
358 | menu->first = entry; | ||
359 | else | ||
360 | iter->next = entry; | ||
361 | |||
362 | iter = entry; | ||
363 | ++i; | ||
364 | } | ||
365 | |||
366 | menu->count = i; | ||
367 | return menu; | ||
368 | |||
369 | cleanup: | ||
370 | bootmenu_destroy(menu); | ||
371 | return NULL; | ||
372 | } | ||
373 | |||
374 | static void bootmenu_show(int delay) | ||
375 | { | ||
376 | int init = 0; | ||
377 | void *choice = NULL; | ||
378 | char *title = NULL; | ||
379 | char *command = NULL; | ||
380 | struct menu *menu; | ||
381 | struct bootmenu_data *bootmenu; | ||
382 | struct bootmenu_entry *iter; | ||
383 | char *option, *sep; | ||
384 | |||
385 | /* If delay is 0 do not create menu, just run first entry */ | ||
386 | if (delay == 0) { | ||
387 | option = bootmenu_getoption(0); | ||
388 | if (!option) { | ||
389 | puts("bootmenu option 0 was not found\n"); | ||
390 | return; | ||
391 | } | ||
392 | sep = strchr(option, '='); | ||
393 | if (!sep) { | ||
394 | puts("bootmenu option 0 is invalid\n"); | ||
395 | return; | ||
396 | } | ||
397 | run_command(sep+1, 0); | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | bootmenu = bootmenu_create(delay); | ||
402 | if (!bootmenu) | ||
403 | return; | ||
404 | |||
405 | menu = menu_create(NULL, bootmenu->delay, 1, bootmenu_print_entry, | ||
406 | bootmenu_choice_entry, bootmenu); | ||
407 | if (!menu) { | ||
408 | bootmenu_destroy(bootmenu); | ||
409 | return; | ||
410 | } | ||
411 | |||
412 | for (iter = bootmenu->first; iter; iter = iter->next) { | ||
413 | if (!menu_item_add(menu, iter->key, iter)) | ||
414 | goto cleanup; | ||
415 | } | ||
416 | |||
417 | /* Default menu entry is always first */ | ||
418 | menu_default_set(menu, "0"); | ||
419 | |||
420 | puts(ANSI_CURSOR_HIDE); | ||
421 | puts(ANSI_CLEAR_CONSOLE); | ||
422 | printf(ANSI_CURSOR_POSITION, 1, 1); | ||
423 | |||
424 | init = 1; | ||
425 | |||
426 | if (menu_get_choice(menu, &choice)) { | ||
427 | iter = choice; | ||
428 | title = strdup(iter->title); | ||
429 | command = strdup(iter->command); | ||
430 | } | ||
431 | |||
432 | cleanup: | ||
433 | menu_destroy(menu); | ||
434 | bootmenu_destroy(bootmenu); | ||
435 | |||
436 | if (init) { | ||
437 | puts(ANSI_CURSOR_SHOW); | ||
438 | puts(ANSI_CLEAR_CONSOLE); | ||
439 | printf(ANSI_CURSOR_POSITION, 1, 1); | ||
440 | } | ||
441 | |||
442 | if (title && command) { | ||
443 | debug("Starting entry '%s'\n", title); | ||
444 | free(title); | ||
445 | run_command(command, 0); | ||
446 | free(command); | ||
447 | } | ||
448 | |||
449 | #ifdef CONFIG_POSTBOOTMENU | ||
450 | run_command(CONFIG_POSTBOOTMENU, 0); | ||
451 | #endif | ||
452 | } | ||
453 | |||
454 | void menu_display_statusline(struct menu *m) | ||
455 | { | ||
456 | struct bootmenu_entry *entry; | ||
457 | struct bootmenu_data *menu; | ||
458 | |||
459 | if (menu_default_choice(m, (void *)&entry) < 0) | ||
460 | return; | ||
461 | |||
462 | menu = entry->menu; | ||
463 | |||
464 | printf(ANSI_CURSOR_POSITION, 1, 1); | ||
465 | puts(ANSI_CLEAR_LINE); | ||
466 | printf(ANSI_CURSOR_POSITION, 2, 1); | ||
467 | puts(" *** U-Boot Boot Menu ***"); | ||
468 | puts(ANSI_CLEAR_LINE_TO_END); | ||
469 | printf(ANSI_CURSOR_POSITION, 3, 1); | ||
470 | puts(ANSI_CLEAR_LINE); | ||
471 | |||
472 | /* First 3 lines are bootmenu header + 2 empty lines between entries */ | ||
473 | printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | ||
474 | puts(ANSI_CLEAR_LINE); | ||
475 | printf(ANSI_CURSOR_POSITION, menu->count + 6, 1); | ||
476 | puts(" Press UP/DOWN to move, ENTER to select"); | ||
477 | puts(ANSI_CLEAR_LINE_TO_END); | ||
478 | printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); | ||
479 | puts(ANSI_CLEAR_LINE); | ||
480 | } | ||
481 | |||
482 | #ifdef CONFIG_MENU_SHOW | ||
483 | int menu_show(int bootdelay) | ||
484 | { | ||
485 | bootmenu_show(bootdelay); | ||
486 | return -1; /* -1 - abort boot and run monitor code */ | ||
487 | } | ||
488 | #endif | ||
489 | |||
490 | int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) | ||
491 | { | ||
492 | char *delay_str = NULL; | ||
493 | int delay = 10; | ||
494 | |||
495 | #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) | ||
496 | delay = CONFIG_BOOTDELAY; | ||
497 | #endif | ||
498 | |||
499 | if (argc >= 2) | ||
500 | delay_str = argv[1]; | ||
501 | |||
502 | if (!delay_str) | ||
503 | delay_str = getenv("bootmenu_delay"); | ||
504 | |||
505 | if (delay_str) | ||
506 | delay = (int)simple_strtol(delay_str, NULL, 10); | ||
507 | |||
508 | bootmenu_show(delay); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | U_BOOT_CMD( | ||
513 | bootmenu, 2, 1, do_bootmenu, | ||
514 | "ANSI terminal bootmenu", | ||
515 | "[delay]\n" | ||
516 | " - show ANSI terminal bootmenu with autoboot delay" | ||
517 | ); | ||
518 |
common/cmd_pxe.c
1 | /* | 1 | /* |
2 | * Copyright 2010-2011 Calxeda, Inc. | 2 | * Copyright 2010-2011 Calxeda, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 5 | * under the terms of the GNU General Public License as published by the Free |
6 | * Software Foundation; either version 2 of the License, or (at your option) | 6 | * Software Foundation; either version 2 of the License, or (at your option) |
7 | * any later version. | 7 | * any later version. |
8 | * | 8 | * |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along with | 14 | * You should have received a copy of the GNU General Public License along with |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | #include <common.h> | 17 | #include <common.h> |
18 | #include <command.h> | 18 | #include <command.h> |
19 | #include <malloc.h> | 19 | #include <malloc.h> |
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/ctype.h> | 21 | #include <linux/ctype.h> |
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | 24 | ||
25 | #include "menu.h" | 25 | #include "menu.h" |
26 | 26 | ||
27 | #define MAX_TFTP_PATH_LEN 127 | 27 | #define MAX_TFTP_PATH_LEN 127 |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * Like getenv, but prints an error if envvar isn't defined in the | 30 | * Like getenv, but prints an error if envvar isn't defined in the |
31 | * environment. It always returns what getenv does, so it can be used in | 31 | * environment. It always returns what getenv does, so it can be used in |
32 | * place of getenv without changing error handling otherwise. | 32 | * place of getenv without changing error handling otherwise. |
33 | */ | 33 | */ |
34 | static char *from_env(char *envvar) | 34 | static char *from_env(char *envvar) |
35 | { | 35 | { |
36 | char *ret; | 36 | char *ret; |
37 | 37 | ||
38 | ret = getenv(envvar); | 38 | ret = getenv(envvar); |
39 | 39 | ||
40 | if (!ret) | 40 | if (!ret) |
41 | printf("missing environment variable: %s\n", envvar); | 41 | printf("missing environment variable: %s\n", envvar); |
42 | 42 | ||
43 | return ret; | 43 | return ret; |
44 | } | 44 | } |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Convert an ethaddr from the environment to the format used by pxelinux | 47 | * Convert an ethaddr from the environment to the format used by pxelinux |
48 | * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to | 48 | * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to |
49 | * the beginning of the ethernet address to indicate a hardware type of | 49 | * the beginning of the ethernet address to indicate a hardware type of |
50 | * Ethernet. Also converts uppercase hex characters into lowercase, to match | 50 | * Ethernet. Also converts uppercase hex characters into lowercase, to match |
51 | * pxelinux's behavior. | 51 | * pxelinux's behavior. |
52 | * | 52 | * |
53 | * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the | 53 | * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the |
54 | * environment, or some other value < 0 on error. | 54 | * environment, or some other value < 0 on error. |
55 | */ | 55 | */ |
56 | static int format_mac_pxe(char *outbuf, size_t outbuf_len) | 56 | static int format_mac_pxe(char *outbuf, size_t outbuf_len) |
57 | { | 57 | { |
58 | size_t ethaddr_len; | 58 | size_t ethaddr_len; |
59 | char *p, *ethaddr; | 59 | char *p, *ethaddr; |
60 | 60 | ||
61 | ethaddr = from_env("ethaddr"); | 61 | ethaddr = from_env("ethaddr"); |
62 | 62 | ||
63 | if (!ethaddr) | 63 | if (!ethaddr) |
64 | return -ENOENT; | 64 | return -ENOENT; |
65 | 65 | ||
66 | ethaddr_len = strlen(ethaddr); | 66 | ethaddr_len = strlen(ethaddr); |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at | 69 | * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at |
70 | * the end. | 70 | * the end. |
71 | */ | 71 | */ |
72 | if (outbuf_len < ethaddr_len + 4) { | 72 | if (outbuf_len < ethaddr_len + 4) { |
73 | printf("outbuf is too small (%d < %d)\n", | 73 | printf("outbuf is too small (%d < %d)\n", |
74 | outbuf_len, ethaddr_len + 4); | 74 | outbuf_len, ethaddr_len + 4); |
75 | 75 | ||
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | } | 77 | } |
78 | 78 | ||
79 | strcpy(outbuf, "01-"); | 79 | strcpy(outbuf, "01-"); |
80 | 80 | ||
81 | for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { | 81 | for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { |
82 | if (*ethaddr == ':') | 82 | if (*ethaddr == ':') |
83 | *p = '-'; | 83 | *p = '-'; |
84 | else | 84 | else |
85 | *p = tolower(*ethaddr); | 85 | *p = tolower(*ethaddr); |
86 | } | 86 | } |
87 | 87 | ||
88 | *p = '\0'; | 88 | *p = '\0'; |
89 | 89 | ||
90 | return 1; | 90 | return 1; |
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Returns the directory the file specified in the bootfile env variable is | 94 | * Returns the directory the file specified in the bootfile env variable is |
95 | * in. If bootfile isn't defined in the environment, return NULL, which should | 95 | * in. If bootfile isn't defined in the environment, return NULL, which should |
96 | * be interpreted as "don't prepend anything to paths". | 96 | * be interpreted as "don't prepend anything to paths". |
97 | */ | 97 | */ |
98 | static int get_bootfile_path(const char *file_path, char *bootfile_path, | 98 | static int get_bootfile_path(const char *file_path, char *bootfile_path, |
99 | size_t bootfile_path_size) | 99 | size_t bootfile_path_size) |
100 | { | 100 | { |
101 | char *bootfile, *last_slash; | 101 | char *bootfile, *last_slash; |
102 | size_t path_len = 0; | 102 | size_t path_len = 0; |
103 | 103 | ||
104 | if (file_path[0] == '/') | 104 | if (file_path[0] == '/') |
105 | goto ret; | 105 | goto ret; |
106 | 106 | ||
107 | bootfile = from_env("bootfile"); | 107 | bootfile = from_env("bootfile"); |
108 | 108 | ||
109 | if (!bootfile) | 109 | if (!bootfile) |
110 | goto ret; | 110 | goto ret; |
111 | 111 | ||
112 | last_slash = strrchr(bootfile, '/'); | 112 | last_slash = strrchr(bootfile, '/'); |
113 | 113 | ||
114 | if (last_slash == NULL) | 114 | if (last_slash == NULL) |
115 | goto ret; | 115 | goto ret; |
116 | 116 | ||
117 | path_len = (last_slash - bootfile) + 1; | 117 | path_len = (last_slash - bootfile) + 1; |
118 | 118 | ||
119 | if (bootfile_path_size < path_len) { | 119 | if (bootfile_path_size < path_len) { |
120 | printf("bootfile_path too small. (%d < %d)\n", | 120 | printf("bootfile_path too small. (%d < %d)\n", |
121 | bootfile_path_size, path_len); | 121 | bootfile_path_size, path_len); |
122 | 122 | ||
123 | return -1; | 123 | return -1; |
124 | } | 124 | } |
125 | 125 | ||
126 | strncpy(bootfile_path, bootfile, path_len); | 126 | strncpy(bootfile_path, bootfile, path_len); |
127 | 127 | ||
128 | ret: | 128 | ret: |
129 | bootfile_path[path_len] = '\0'; | 129 | bootfile_path[path_len] = '\0'; |
130 | 130 | ||
131 | return 1; | 131 | return 1; |
132 | } | 132 | } |
133 | 133 | ||
134 | static int (*do_getfile)(char *file_path, char *file_addr); | 134 | static int (*do_getfile)(char *file_path, char *file_addr); |
135 | 135 | ||
136 | static int do_get_tftp(char *file_path, char *file_addr) | 136 | static int do_get_tftp(char *file_path, char *file_addr) |
137 | { | 137 | { |
138 | char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; | 138 | char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; |
139 | 139 | ||
140 | tftp_argv[1] = file_addr; | 140 | tftp_argv[1] = file_addr; |
141 | tftp_argv[2] = file_path; | 141 | tftp_argv[2] = file_path; |
142 | 142 | ||
143 | if (do_tftpb(NULL, 0, 3, tftp_argv)) | 143 | if (do_tftpb(NULL, 0, 3, tftp_argv)) |
144 | return -ENOENT; | 144 | return -ENOENT; |
145 | 145 | ||
146 | return 1; | 146 | return 1; |
147 | } | 147 | } |
148 | 148 | ||
149 | static char *fs_argv[5]; | 149 | static char *fs_argv[5]; |
150 | 150 | ||
151 | static int do_get_ext2(char *file_path, char *file_addr) | 151 | static int do_get_ext2(char *file_path, char *file_addr) |
152 | { | 152 | { |
153 | #ifdef CONFIG_CMD_EXT2 | 153 | #ifdef CONFIG_CMD_EXT2 |
154 | fs_argv[0] = "ext2load"; | 154 | fs_argv[0] = "ext2load"; |
155 | fs_argv[3] = file_addr; | 155 | fs_argv[3] = file_addr; |
156 | fs_argv[4] = file_path; | 156 | fs_argv[4] = file_path; |
157 | 157 | ||
158 | if (!do_ext2load(NULL, 0, 5, fs_argv)) | 158 | if (!do_ext2load(NULL, 0, 5, fs_argv)) |
159 | return 1; | 159 | return 1; |
160 | #endif | 160 | #endif |
161 | return -ENOENT; | 161 | return -ENOENT; |
162 | } | 162 | } |
163 | 163 | ||
164 | static int do_get_fat(char *file_path, char *file_addr) | 164 | static int do_get_fat(char *file_path, char *file_addr) |
165 | { | 165 | { |
166 | #ifdef CONFIG_CMD_FAT | 166 | #ifdef CONFIG_CMD_FAT |
167 | fs_argv[0] = "fatload"; | 167 | fs_argv[0] = "fatload"; |
168 | fs_argv[3] = file_addr; | 168 | fs_argv[3] = file_addr; |
169 | fs_argv[4] = file_path; | 169 | fs_argv[4] = file_path; |
170 | 170 | ||
171 | if (!do_fat_fsload(NULL, 0, 5, fs_argv)) | 171 | if (!do_fat_fsload(NULL, 0, 5, fs_argv)) |
172 | return 1; | 172 | return 1; |
173 | #endif | 173 | #endif |
174 | return -ENOENT; | 174 | return -ENOENT; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * As in pxelinux, paths to files referenced from files we retrieve are | 178 | * As in pxelinux, paths to files referenced from files we retrieve are |
179 | * relative to the location of bootfile. get_relfile takes such a path and | 179 | * relative to the location of bootfile. get_relfile takes such a path and |
180 | * joins it with the bootfile path to get the full path to the target file. If | 180 | * joins it with the bootfile path to get the full path to the target file. If |
181 | * the bootfile path is NULL, we use file_path as is. | 181 | * the bootfile path is NULL, we use file_path as is. |
182 | * | 182 | * |
183 | * Returns 1 for success, or < 0 on error. | 183 | * Returns 1 for success, or < 0 on error. |
184 | */ | 184 | */ |
185 | static int get_relfile(char *file_path, void *file_addr) | 185 | static int get_relfile(char *file_path, void *file_addr) |
186 | { | 186 | { |
187 | size_t path_len; | 187 | size_t path_len; |
188 | char relfile[MAX_TFTP_PATH_LEN+1]; | 188 | char relfile[MAX_TFTP_PATH_LEN+1]; |
189 | char addr_buf[10]; | 189 | char addr_buf[10]; |
190 | int err; | 190 | int err; |
191 | 191 | ||
192 | err = get_bootfile_path(file_path, relfile, sizeof(relfile)); | 192 | err = get_bootfile_path(file_path, relfile, sizeof(relfile)); |
193 | 193 | ||
194 | if (err < 0) | 194 | if (err < 0) |
195 | return err; | 195 | return err; |
196 | 196 | ||
197 | path_len = strlen(file_path); | 197 | path_len = strlen(file_path); |
198 | path_len += strlen(relfile); | 198 | path_len += strlen(relfile); |
199 | 199 | ||
200 | if (path_len > MAX_TFTP_PATH_LEN) { | 200 | if (path_len > MAX_TFTP_PATH_LEN) { |
201 | printf("Base path too long (%s%s)\n", | 201 | printf("Base path too long (%s%s)\n", |
202 | relfile, | 202 | relfile, |
203 | file_path); | 203 | file_path); |
204 | 204 | ||
205 | return -ENAMETOOLONG; | 205 | return -ENAMETOOLONG; |
206 | } | 206 | } |
207 | 207 | ||
208 | strcat(relfile, file_path); | 208 | strcat(relfile, file_path); |
209 | 209 | ||
210 | printf("Retrieving file: %s\n", relfile); | 210 | printf("Retrieving file: %s\n", relfile); |
211 | 211 | ||
212 | sprintf(addr_buf, "%p", file_addr); | 212 | sprintf(addr_buf, "%p", file_addr); |
213 | 213 | ||
214 | return do_getfile(relfile, addr_buf); | 214 | return do_getfile(relfile, addr_buf); |
215 | } | 215 | } |
216 | 216 | ||
217 | /* | 217 | /* |
218 | * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If | 218 | * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If |
219 | * 'bootfile' was specified in the environment, the path to bootfile will be | 219 | * 'bootfile' was specified in the environment, the path to bootfile will be |
220 | * prepended to 'file_path' and the resulting path will be used. | 220 | * prepended to 'file_path' and the resulting path will be used. |
221 | * | 221 | * |
222 | * Returns 1 on success, or < 0 for error. | 222 | * Returns 1 on success, or < 0 for error. |
223 | */ | 223 | */ |
224 | static int get_pxe_file(char *file_path, void *file_addr) | 224 | static int get_pxe_file(char *file_path, void *file_addr) |
225 | { | 225 | { |
226 | unsigned long config_file_size; | 226 | unsigned long config_file_size; |
227 | char *tftp_filesize; | 227 | char *tftp_filesize; |
228 | int err; | 228 | int err; |
229 | 229 | ||
230 | err = get_relfile(file_path, file_addr); | 230 | err = get_relfile(file_path, file_addr); |
231 | 231 | ||
232 | if (err < 0) | 232 | if (err < 0) |
233 | return err; | 233 | return err; |
234 | 234 | ||
235 | /* | 235 | /* |
236 | * the file comes without a NUL byte at the end, so find out its size | 236 | * the file comes without a NUL byte at the end, so find out its size |
237 | * and add the NUL byte. | 237 | * and add the NUL byte. |
238 | */ | 238 | */ |
239 | tftp_filesize = from_env("filesize"); | 239 | tftp_filesize = from_env("filesize"); |
240 | 240 | ||
241 | if (!tftp_filesize) | 241 | if (!tftp_filesize) |
242 | return -ENOENT; | 242 | return -ENOENT; |
243 | 243 | ||
244 | if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0) | 244 | if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0) |
245 | return -EINVAL; | 245 | return -EINVAL; |
246 | 246 | ||
247 | *(char *)(file_addr + config_file_size) = '\0'; | 247 | *(char *)(file_addr + config_file_size) = '\0'; |
248 | 248 | ||
249 | return 1; | 249 | return 1; |
250 | } | 250 | } |
251 | 251 | ||
252 | #define PXELINUX_DIR "pxelinux.cfg/" | 252 | #define PXELINUX_DIR "pxelinux.cfg/" |
253 | 253 | ||
254 | /* | 254 | /* |
255 | * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file | 255 | * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file |
256 | * to do the hard work, the location of the 'pxelinux.cfg' folder is generated | 256 | * to do the hard work, the location of the 'pxelinux.cfg' folder is generated |
257 | * from the bootfile path, as described above. | 257 | * from the bootfile path, as described above. |
258 | * | 258 | * |
259 | * Returns 1 on success or < 0 on error. | 259 | * Returns 1 on success or < 0 on error. |
260 | */ | 260 | */ |
261 | static int get_pxelinux_path(char *file, void *pxefile_addr_r) | 261 | static int get_pxelinux_path(char *file, void *pxefile_addr_r) |
262 | { | 262 | { |
263 | size_t base_len = strlen(PXELINUX_DIR); | 263 | size_t base_len = strlen(PXELINUX_DIR); |
264 | char path[MAX_TFTP_PATH_LEN+1]; | 264 | char path[MAX_TFTP_PATH_LEN+1]; |
265 | 265 | ||
266 | if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) { | 266 | if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) { |
267 | printf("path (%s%s) too long, skipping\n", | 267 | printf("path (%s%s) too long, skipping\n", |
268 | PXELINUX_DIR, file); | 268 | PXELINUX_DIR, file); |
269 | return -ENAMETOOLONG; | 269 | return -ENAMETOOLONG; |
270 | } | 270 | } |
271 | 271 | ||
272 | sprintf(path, PXELINUX_DIR "%s", file); | 272 | sprintf(path, PXELINUX_DIR "%s", file); |
273 | 273 | ||
274 | return get_pxe_file(path, pxefile_addr_r); | 274 | return get_pxe_file(path, pxefile_addr_r); |
275 | } | 275 | } |
276 | 276 | ||
277 | /* | 277 | /* |
278 | * Looks for a pxe file with a name based on the pxeuuid environment variable. | 278 | * Looks for a pxe file with a name based on the pxeuuid environment variable. |
279 | * | 279 | * |
280 | * Returns 1 on success or < 0 on error. | 280 | * Returns 1 on success or < 0 on error. |
281 | */ | 281 | */ |
282 | static int pxe_uuid_path(void *pxefile_addr_r) | 282 | static int pxe_uuid_path(void *pxefile_addr_r) |
283 | { | 283 | { |
284 | char *uuid_str; | 284 | char *uuid_str; |
285 | 285 | ||
286 | uuid_str = from_env("pxeuuid"); | 286 | uuid_str = from_env("pxeuuid"); |
287 | 287 | ||
288 | if (!uuid_str) | 288 | if (!uuid_str) |
289 | return -ENOENT; | 289 | return -ENOENT; |
290 | 290 | ||
291 | return get_pxelinux_path(uuid_str, pxefile_addr_r); | 291 | return get_pxelinux_path(uuid_str, pxefile_addr_r); |
292 | } | 292 | } |
293 | 293 | ||
294 | /* | 294 | /* |
295 | * Looks for a pxe file with a name based on the 'ethaddr' environment | 295 | * Looks for a pxe file with a name based on the 'ethaddr' environment |
296 | * variable. | 296 | * variable. |
297 | * | 297 | * |
298 | * Returns 1 on success or < 0 on error. | 298 | * Returns 1 on success or < 0 on error. |
299 | */ | 299 | */ |
300 | static int pxe_mac_path(void *pxefile_addr_r) | 300 | static int pxe_mac_path(void *pxefile_addr_r) |
301 | { | 301 | { |
302 | char mac_str[21]; | 302 | char mac_str[21]; |
303 | int err; | 303 | int err; |
304 | 304 | ||
305 | err = format_mac_pxe(mac_str, sizeof(mac_str)); | 305 | err = format_mac_pxe(mac_str, sizeof(mac_str)); |
306 | 306 | ||
307 | if (err < 0) | 307 | if (err < 0) |
308 | return err; | 308 | return err; |
309 | 309 | ||
310 | return get_pxelinux_path(mac_str, pxefile_addr_r); | 310 | return get_pxelinux_path(mac_str, pxefile_addr_r); |
311 | } | 311 | } |
312 | 312 | ||
313 | /* | 313 | /* |
314 | * Looks for pxe files with names based on our IP address. See pxelinux | 314 | * Looks for pxe files with names based on our IP address. See pxelinux |
315 | * documentation for details on what these file names look like. We match | 315 | * documentation for details on what these file names look like. We match |
316 | * that exactly. | 316 | * that exactly. |
317 | * | 317 | * |
318 | * Returns 1 on success or < 0 on error. | 318 | * Returns 1 on success or < 0 on error. |
319 | */ | 319 | */ |
320 | static int pxe_ipaddr_paths(void *pxefile_addr_r) | 320 | static int pxe_ipaddr_paths(void *pxefile_addr_r) |
321 | { | 321 | { |
322 | char ip_addr[9]; | 322 | char ip_addr[9]; |
323 | int mask_pos, err; | 323 | int mask_pos, err; |
324 | 324 | ||
325 | sprintf(ip_addr, "%08X", ntohl(NetOurIP)); | 325 | sprintf(ip_addr, "%08X", ntohl(NetOurIP)); |
326 | 326 | ||
327 | for (mask_pos = 7; mask_pos >= 0; mask_pos--) { | 327 | for (mask_pos = 7; mask_pos >= 0; mask_pos--) { |
328 | err = get_pxelinux_path(ip_addr, pxefile_addr_r); | 328 | err = get_pxelinux_path(ip_addr, pxefile_addr_r); |
329 | 329 | ||
330 | if (err > 0) | 330 | if (err > 0) |
331 | return err; | 331 | return err; |
332 | 332 | ||
333 | ip_addr[mask_pos] = '\0'; | 333 | ip_addr[mask_pos] = '\0'; |
334 | } | 334 | } |
335 | 335 | ||
336 | return -ENOENT; | 336 | return -ENOENT; |
337 | } | 337 | } |
338 | 338 | ||
339 | /* | 339 | /* |
340 | * Entry point for the 'pxe get' command. | 340 | * Entry point for the 'pxe get' command. |
341 | * This Follows pxelinux's rules to download a config file from a tftp server. | 341 | * This Follows pxelinux's rules to download a config file from a tftp server. |
342 | * The file is stored at the location given by the pxefile_addr_r environment | 342 | * The file is stored at the location given by the pxefile_addr_r environment |
343 | * variable, which must be set. | 343 | * variable, which must be set. |
344 | * | 344 | * |
345 | * UUID comes from pxeuuid env variable, if defined | 345 | * UUID comes from pxeuuid env variable, if defined |
346 | * MAC addr comes from ethaddr env variable, if defined | 346 | * MAC addr comes from ethaddr env variable, if defined |
347 | * IP | 347 | * IP |
348 | * | 348 | * |
349 | * see http://syslinux.zytor.com/wiki/index.php/PXELINUX | 349 | * see http://syslinux.zytor.com/wiki/index.php/PXELINUX |
350 | * | 350 | * |
351 | * Returns 0 on success or 1 on error. | 351 | * Returns 0 on success or 1 on error. |
352 | */ | 352 | */ |
353 | static int | 353 | static int |
354 | do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 354 | do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
355 | { | 355 | { |
356 | char *pxefile_addr_str; | 356 | char *pxefile_addr_str; |
357 | unsigned long pxefile_addr_r; | 357 | unsigned long pxefile_addr_r; |
358 | int err; | 358 | int err; |
359 | 359 | ||
360 | do_getfile = do_get_tftp; | 360 | do_getfile = do_get_tftp; |
361 | 361 | ||
362 | if (argc != 1) | 362 | if (argc != 1) |
363 | return CMD_RET_USAGE; | 363 | return CMD_RET_USAGE; |
364 | 364 | ||
365 | pxefile_addr_str = from_env("pxefile_addr_r"); | 365 | pxefile_addr_str = from_env("pxefile_addr_r"); |
366 | 366 | ||
367 | if (!pxefile_addr_str) | 367 | if (!pxefile_addr_str) |
368 | return 1; | 368 | return 1; |
369 | 369 | ||
370 | err = strict_strtoul(pxefile_addr_str, 16, | 370 | err = strict_strtoul(pxefile_addr_str, 16, |
371 | (unsigned long *)&pxefile_addr_r); | 371 | (unsigned long *)&pxefile_addr_r); |
372 | if (err < 0) | 372 | if (err < 0) |
373 | return 1; | 373 | return 1; |
374 | 374 | ||
375 | /* | 375 | /* |
376 | * Keep trying paths until we successfully get a file we're looking | 376 | * Keep trying paths until we successfully get a file we're looking |
377 | * for. | 377 | * for. |
378 | */ | 378 | */ |
379 | if (pxe_uuid_path((void *)pxefile_addr_r) > 0 | 379 | if (pxe_uuid_path((void *)pxefile_addr_r) > 0 |
380 | || pxe_mac_path((void *)pxefile_addr_r) > 0 | 380 | || pxe_mac_path((void *)pxefile_addr_r) > 0 |
381 | || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 | 381 | || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 |
382 | || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { | 382 | || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { |
383 | 383 | ||
384 | printf("Config file found\n"); | 384 | printf("Config file found\n"); |
385 | 385 | ||
386 | return 0; | 386 | return 0; |
387 | } | 387 | } |
388 | 388 | ||
389 | printf("Config file not found\n"); | 389 | printf("Config file not found\n"); |
390 | 390 | ||
391 | return 1; | 391 | return 1; |
392 | } | 392 | } |
393 | 393 | ||
394 | /* | 394 | /* |
395 | * Wrapper to make it easier to store the file at file_path in the location | 395 | * Wrapper to make it easier to store the file at file_path in the location |
396 | * specified by envaddr_name. file_path will be joined to the bootfile path, | 396 | * specified by envaddr_name. file_path will be joined to the bootfile path, |
397 | * if any is specified. | 397 | * if any is specified. |
398 | * | 398 | * |
399 | * Returns 1 on success or < 0 on error. | 399 | * Returns 1 on success or < 0 on error. |
400 | */ | 400 | */ |
401 | static int get_relfile_envaddr(char *file_path, char *envaddr_name) | 401 | static int get_relfile_envaddr(char *file_path, char *envaddr_name) |
402 | { | 402 | { |
403 | unsigned long file_addr; | 403 | unsigned long file_addr; |
404 | char *envaddr; | 404 | char *envaddr; |
405 | 405 | ||
406 | envaddr = from_env(envaddr_name); | 406 | envaddr = from_env(envaddr_name); |
407 | 407 | ||
408 | if (!envaddr) | 408 | if (!envaddr) |
409 | return -ENOENT; | 409 | return -ENOENT; |
410 | 410 | ||
411 | if (strict_strtoul(envaddr, 16, &file_addr) < 0) | 411 | if (strict_strtoul(envaddr, 16, &file_addr) < 0) |
412 | return -EINVAL; | 412 | return -EINVAL; |
413 | 413 | ||
414 | return get_relfile(file_path, (void *)file_addr); | 414 | return get_relfile(file_path, (void *)file_addr); |
415 | } | 415 | } |
416 | 416 | ||
417 | /* | 417 | /* |
418 | * A note on the pxe file parser. | 418 | * A note on the pxe file parser. |
419 | * | 419 | * |
420 | * We're parsing files that use syslinux grammar, which has a few quirks. | 420 | * We're parsing files that use syslinux grammar, which has a few quirks. |
421 | * String literals must be recognized based on context - there is no | 421 | * String literals must be recognized based on context - there is no |
422 | * quoting or escaping support. There's also nothing to explicitly indicate | 422 | * quoting or escaping support. There's also nothing to explicitly indicate |
423 | * when a label section completes. We deal with that by ending a label | 423 | * when a label section completes. We deal with that by ending a label |
424 | * section whenever we see a line that doesn't include. | 424 | * section whenever we see a line that doesn't include. |
425 | * | 425 | * |
426 | * As with the syslinux family, this same file format could be reused in the | 426 | * As with the syslinux family, this same file format could be reused in the |
427 | * future for non pxe purposes. The only action it takes during parsing that | 427 | * future for non pxe purposes. The only action it takes during parsing that |
428 | * would throw this off is handling of include files. It assumes we're using | 428 | * would throw this off is handling of include files. It assumes we're using |
429 | * pxe, and does a tftp download of a file listed as an include file in the | 429 | * pxe, and does a tftp download of a file listed as an include file in the |
430 | * middle of the parsing operation. That could be handled by refactoring it to | 430 | * middle of the parsing operation. That could be handled by refactoring it to |
431 | * take a 'include file getter' function. | 431 | * take a 'include file getter' function. |
432 | */ | 432 | */ |
433 | 433 | ||
434 | /* | 434 | /* |
435 | * Describes a single label given in a pxe file. | 435 | * Describes a single label given in a pxe file. |
436 | * | 436 | * |
437 | * Create these with the 'label_create' function given below. | 437 | * Create these with the 'label_create' function given below. |
438 | * | 438 | * |
439 | * name - the name of the menu as given on the 'menu label' line. | 439 | * name - the name of the menu as given on the 'menu label' line. |
440 | * kernel - the path to the kernel file to use for this label. | 440 | * kernel - the path to the kernel file to use for this label. |
441 | * append - kernel command line to use when booting this label | 441 | * append - kernel command line to use when booting this label |
442 | * initrd - path to the initrd to use for this label. | 442 | * initrd - path to the initrd to use for this label. |
443 | * attempted - 0 if we haven't tried to boot this label, 1 if we have. | 443 | * attempted - 0 if we haven't tried to boot this label, 1 if we have. |
444 | * localboot - 1 if this label specified 'localboot', 0 otherwise. | 444 | * localboot - 1 if this label specified 'localboot', 0 otherwise. |
445 | * list - lets these form a list, which a pxe_menu struct will hold. | 445 | * list - lets these form a list, which a pxe_menu struct will hold. |
446 | */ | 446 | */ |
447 | struct pxe_label { | 447 | struct pxe_label { |
448 | char *name; | 448 | char *name; |
449 | char *menu; | 449 | char *menu; |
450 | char *kernel; | 450 | char *kernel; |
451 | char *append; | 451 | char *append; |
452 | char *initrd; | 452 | char *initrd; |
453 | char *fdt; | 453 | char *fdt; |
454 | int attempted; | 454 | int attempted; |
455 | int localboot; | 455 | int localboot; |
456 | struct list_head list; | 456 | struct list_head list; |
457 | }; | 457 | }; |
458 | 458 | ||
459 | /* | 459 | /* |
460 | * Describes a pxe menu as given via pxe files. | 460 | * Describes a pxe menu as given via pxe files. |
461 | * | 461 | * |
462 | * title - the name of the menu as given by a 'menu title' line. | 462 | * title - the name of the menu as given by a 'menu title' line. |
463 | * default_label - the name of the default label, if any. | 463 | * default_label - the name of the default label, if any. |
464 | * timeout - time in tenths of a second to wait for a user key-press before | 464 | * timeout - time in tenths of a second to wait for a user key-press before |
465 | * booting the default label. | 465 | * booting the default label. |
466 | * prompt - if 0, don't prompt for a choice unless the timeout period is | 466 | * prompt - if 0, don't prompt for a choice unless the timeout period is |
467 | * interrupted. If 1, always prompt for a choice regardless of | 467 | * interrupted. If 1, always prompt for a choice regardless of |
468 | * timeout. | 468 | * timeout. |
469 | * labels - a list of labels defined for the menu. | 469 | * labels - a list of labels defined for the menu. |
470 | */ | 470 | */ |
471 | struct pxe_menu { | 471 | struct pxe_menu { |
472 | char *title; | 472 | char *title; |
473 | char *default_label; | 473 | char *default_label; |
474 | int timeout; | 474 | int timeout; |
475 | int prompt; | 475 | int prompt; |
476 | struct list_head labels; | 476 | struct list_head labels; |
477 | }; | 477 | }; |
478 | 478 | ||
479 | /* | 479 | /* |
480 | * Allocates memory for and initializes a pxe_label. This uses malloc, so the | 480 | * Allocates memory for and initializes a pxe_label. This uses malloc, so the |
481 | * result must be free()'d to reclaim the memory. | 481 | * result must be free()'d to reclaim the memory. |
482 | * | 482 | * |
483 | * Returns NULL if malloc fails. | 483 | * Returns NULL if malloc fails. |
484 | */ | 484 | */ |
485 | static struct pxe_label *label_create(void) | 485 | static struct pxe_label *label_create(void) |
486 | { | 486 | { |
487 | struct pxe_label *label; | 487 | struct pxe_label *label; |
488 | 488 | ||
489 | label = malloc(sizeof(struct pxe_label)); | 489 | label = malloc(sizeof(struct pxe_label)); |
490 | 490 | ||
491 | if (!label) | 491 | if (!label) |
492 | return NULL; | 492 | return NULL; |
493 | 493 | ||
494 | memset(label, 0, sizeof(struct pxe_label)); | 494 | memset(label, 0, sizeof(struct pxe_label)); |
495 | 495 | ||
496 | return label; | 496 | return label; |
497 | } | 497 | } |
498 | 498 | ||
499 | /* | 499 | /* |
500 | * Free the memory used by a pxe_label, including that used by its name, | 500 | * Free the memory used by a pxe_label, including that used by its name, |
501 | * kernel, append and initrd members, if they're non NULL. | 501 | * kernel, append and initrd members, if they're non NULL. |
502 | * | 502 | * |
503 | * So - be sure to only use dynamically allocated memory for the members of | 503 | * So - be sure to only use dynamically allocated memory for the members of |
504 | * the pxe_label struct, unless you want to clean it up first. These are | 504 | * the pxe_label struct, unless you want to clean it up first. These are |
505 | * currently only created by the pxe file parsing code. | 505 | * currently only created by the pxe file parsing code. |
506 | */ | 506 | */ |
507 | static void label_destroy(struct pxe_label *label) | 507 | static void label_destroy(struct pxe_label *label) |
508 | { | 508 | { |
509 | if (label->name) | 509 | if (label->name) |
510 | free(label->name); | 510 | free(label->name); |
511 | 511 | ||
512 | if (label->kernel) | 512 | if (label->kernel) |
513 | free(label->kernel); | 513 | free(label->kernel); |
514 | 514 | ||
515 | if (label->append) | 515 | if (label->append) |
516 | free(label->append); | 516 | free(label->append); |
517 | 517 | ||
518 | if (label->initrd) | 518 | if (label->initrd) |
519 | free(label->initrd); | 519 | free(label->initrd); |
520 | 520 | ||
521 | if (label->fdt) | 521 | if (label->fdt) |
522 | free(label->fdt); | 522 | free(label->fdt); |
523 | 523 | ||
524 | free(label); | 524 | free(label); |
525 | } | 525 | } |
526 | 526 | ||
527 | /* | 527 | /* |
528 | * Print a label and its string members if they're defined. | 528 | * Print a label and its string members if they're defined. |
529 | * | 529 | * |
530 | * This is passed as a callback to the menu code for displaying each | 530 | * This is passed as a callback to the menu code for displaying each |
531 | * menu entry. | 531 | * menu entry. |
532 | */ | 532 | */ |
533 | static void label_print(void *data) | 533 | static void label_print(void *data) |
534 | { | 534 | { |
535 | struct pxe_label *label = data; | 535 | struct pxe_label *label = data; |
536 | const char *c = label->menu ? label->menu : label->kernel; | 536 | const char *c = label->menu ? label->menu : label->kernel; |
537 | 537 | ||
538 | printf("%s:\t%s\n", label->name, c); | 538 | printf("%s:\t%s\n", label->name, c); |
539 | 539 | ||
540 | if (label->kernel) | 540 | if (label->kernel) |
541 | printf("\t\tkernel: %s\n", label->kernel); | 541 | printf("\t\tkernel: %s\n", label->kernel); |
542 | 542 | ||
543 | if (label->append) | 543 | if (label->append) |
544 | printf("\t\tappend: %s\n", label->append); | 544 | printf("\t\tappend: %s\n", label->append); |
545 | 545 | ||
546 | if (label->initrd) | 546 | if (label->initrd) |
547 | printf("\t\tinitrd: %s\n", label->initrd); | 547 | printf("\t\tinitrd: %s\n", label->initrd); |
548 | 548 | ||
549 | if (label->fdt) | 549 | if (label->fdt) |
550 | printf("\tfdt: %s\n", label->fdt); | 550 | printf("\tfdt: %s\n", label->fdt); |
551 | } | 551 | } |
552 | 552 | ||
553 | /* | 553 | /* |
554 | * Boot a label that specified 'localboot'. This requires that the 'localcmd' | 554 | * Boot a label that specified 'localboot'. This requires that the 'localcmd' |
555 | * environment variable is defined. Its contents will be executed as U-boot | 555 | * environment variable is defined. Its contents will be executed as U-boot |
556 | * command. If the label specified an 'append' line, its contents will be | 556 | * command. If the label specified an 'append' line, its contents will be |
557 | * used to overwrite the contents of the 'bootargs' environment variable prior | 557 | * used to overwrite the contents of the 'bootargs' environment variable prior |
558 | * to running 'localcmd'. | 558 | * to running 'localcmd'. |
559 | * | 559 | * |
560 | * Returns 1 on success or < 0 on error. | 560 | * Returns 1 on success or < 0 on error. |
561 | */ | 561 | */ |
562 | static int label_localboot(struct pxe_label *label) | 562 | static int label_localboot(struct pxe_label *label) |
563 | { | 563 | { |
564 | char *localcmd; | 564 | char *localcmd; |
565 | 565 | ||
566 | localcmd = from_env("localcmd"); | 566 | localcmd = from_env("localcmd"); |
567 | 567 | ||
568 | if (!localcmd) | 568 | if (!localcmd) |
569 | return -ENOENT; | 569 | return -ENOENT; |
570 | 570 | ||
571 | if (label->append) | 571 | if (label->append) |
572 | setenv("bootargs", label->append); | 572 | setenv("bootargs", label->append); |
573 | 573 | ||
574 | debug("running: %s\n", localcmd); | 574 | debug("running: %s\n", localcmd); |
575 | 575 | ||
576 | return run_command_list(localcmd, strlen(localcmd), 0); | 576 | return run_command_list(localcmd, strlen(localcmd), 0); |
577 | } | 577 | } |
578 | 578 | ||
579 | /* | 579 | /* |
580 | * Boot according to the contents of a pxe_label. | 580 | * Boot according to the contents of a pxe_label. |
581 | * | 581 | * |
582 | * If we can't boot for any reason, we return. A successful boot never | 582 | * If we can't boot for any reason, we return. A successful boot never |
583 | * returns. | 583 | * returns. |
584 | * | 584 | * |
585 | * The kernel will be stored in the location given by the 'kernel_addr_r' | 585 | * The kernel will be stored in the location given by the 'kernel_addr_r' |
586 | * environment variable. | 586 | * environment variable. |
587 | * | 587 | * |
588 | * If the label specifies an initrd file, it will be stored in the location | 588 | * If the label specifies an initrd file, it will be stored in the location |
589 | * given by the 'ramdisk_addr_r' environment variable. | 589 | * given by the 'ramdisk_addr_r' environment variable. |
590 | * | 590 | * |
591 | * If the label specifies an 'append' line, its contents will overwrite that | 591 | * If the label specifies an 'append' line, its contents will overwrite that |
592 | * of the 'bootargs' environment variable. | 592 | * of the 'bootargs' environment variable. |
593 | */ | 593 | */ |
594 | static void label_boot(struct pxe_label *label) | 594 | static void label_boot(struct pxe_label *label) |
595 | { | 595 | { |
596 | char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; | 596 | char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; |
597 | int bootm_argc = 3; | 597 | int bootm_argc = 3; |
598 | 598 | ||
599 | label_print(label); | 599 | label_print(label); |
600 | 600 | ||
601 | label->attempted = 1; | 601 | label->attempted = 1; |
602 | 602 | ||
603 | if (label->localboot) { | 603 | if (label->localboot) { |
604 | label_localboot(label); | 604 | label_localboot(label); |
605 | return; | 605 | return; |
606 | } | 606 | } |
607 | 607 | ||
608 | if (label->kernel == NULL) { | 608 | if (label->kernel == NULL) { |
609 | printf("No kernel given, skipping %s\n", | 609 | printf("No kernel given, skipping %s\n", |
610 | label->name); | 610 | label->name); |
611 | return; | 611 | return; |
612 | } | 612 | } |
613 | 613 | ||
614 | if (label->initrd) { | 614 | if (label->initrd) { |
615 | if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) { | 615 | if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) { |
616 | printf("Skipping %s for failure retrieving initrd\n", | 616 | printf("Skipping %s for failure retrieving initrd\n", |
617 | label->name); | 617 | label->name); |
618 | return; | 618 | return; |
619 | } | 619 | } |
620 | 620 | ||
621 | bootm_argv[2] = getenv("ramdisk_addr_r"); | 621 | bootm_argv[2] = getenv("ramdisk_addr_r"); |
622 | } else { | 622 | } else { |
623 | bootm_argv[2] = "-"; | 623 | bootm_argv[2] = "-"; |
624 | } | 624 | } |
625 | 625 | ||
626 | if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) { | 626 | if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) { |
627 | printf("Skipping %s for failure retrieving kernel\n", | 627 | printf("Skipping %s for failure retrieving kernel\n", |
628 | label->name); | 628 | label->name); |
629 | return; | 629 | return; |
630 | } | 630 | } |
631 | 631 | ||
632 | if (label->append) | 632 | if (label->append) |
633 | setenv("bootargs", label->append); | 633 | setenv("bootargs", label->append); |
634 | 634 | ||
635 | bootm_argv[1] = getenv("kernel_addr_r"); | 635 | bootm_argv[1] = getenv("kernel_addr_r"); |
636 | 636 | ||
637 | /* | 637 | /* |
638 | * fdt usage is optional: | 638 | * fdt usage is optional: |
639 | * It handles the following scenarios. All scenarios are exclusive | 639 | * It handles the following scenarios. All scenarios are exclusive |
640 | * | 640 | * |
641 | * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in | 641 | * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in |
642 | * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm, | 642 | * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm, |
643 | * and adjust argc appropriately. | 643 | * and adjust argc appropriately. |
644 | * | 644 | * |
645 | * Scenario 2: If there is an fdt_addr specified, pass it along to | 645 | * Scenario 2: If there is an fdt_addr specified, pass it along to |
646 | * bootm, and adjust argc appropriately. | 646 | * bootm, and adjust argc appropriately. |
647 | * | 647 | * |
648 | * Scenario 3: fdt blob is not available. | 648 | * Scenario 3: fdt blob is not available. |
649 | */ | 649 | */ |
650 | bootm_argv[3] = getenv("fdt_addr_r"); | 650 | bootm_argv[3] = getenv("fdt_addr_r"); |
651 | 651 | ||
652 | /* if fdt label is defined then get fdt from server */ | 652 | /* if fdt label is defined then get fdt from server */ |
653 | if (bootm_argv[3] && label->fdt) { | 653 | if (bootm_argv[3] && label->fdt) { |
654 | if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) { | 654 | if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) { |
655 | printf("Skipping %s for failure retrieving fdt\n", | 655 | printf("Skipping %s for failure retrieving fdt\n", |
656 | label->name); | 656 | label->name); |
657 | return; | 657 | return; |
658 | } | 658 | } |
659 | } else | 659 | } else |
660 | bootm_argv[3] = getenv("fdt_addr"); | 660 | bootm_argv[3] = getenv("fdt_addr"); |
661 | 661 | ||
662 | if (bootm_argv[3]) | 662 | if (bootm_argv[3]) |
663 | bootm_argc = 4; | 663 | bootm_argc = 4; |
664 | 664 | ||
665 | do_bootm(NULL, 0, bootm_argc, bootm_argv); | 665 | do_bootm(NULL, 0, bootm_argc, bootm_argv); |
666 | } | 666 | } |
667 | 667 | ||
668 | /* | 668 | /* |
669 | * Tokens for the pxe file parser. | 669 | * Tokens for the pxe file parser. |
670 | */ | 670 | */ |
671 | enum token_type { | 671 | enum token_type { |
672 | T_EOL, | 672 | T_EOL, |
673 | T_STRING, | 673 | T_STRING, |
674 | T_EOF, | 674 | T_EOF, |
675 | T_MENU, | 675 | T_MENU, |
676 | T_TITLE, | 676 | T_TITLE, |
677 | T_TIMEOUT, | 677 | T_TIMEOUT, |
678 | T_LABEL, | 678 | T_LABEL, |
679 | T_KERNEL, | 679 | T_KERNEL, |
680 | T_LINUX, | 680 | T_LINUX, |
681 | T_APPEND, | 681 | T_APPEND, |
682 | T_INITRD, | 682 | T_INITRD, |
683 | T_LOCALBOOT, | 683 | T_LOCALBOOT, |
684 | T_DEFAULT, | 684 | T_DEFAULT, |
685 | T_PROMPT, | 685 | T_PROMPT, |
686 | T_INCLUDE, | 686 | T_INCLUDE, |
687 | T_FDT, | 687 | T_FDT, |
688 | T_INVALID | 688 | T_INVALID |
689 | }; | 689 | }; |
690 | 690 | ||
691 | /* | 691 | /* |
692 | * A token - given by a value and a type. | 692 | * A token - given by a value and a type. |
693 | */ | 693 | */ |
694 | struct token { | 694 | struct token { |
695 | char *val; | 695 | char *val; |
696 | enum token_type type; | 696 | enum token_type type; |
697 | }; | 697 | }; |
698 | 698 | ||
699 | /* | 699 | /* |
700 | * Keywords recognized. | 700 | * Keywords recognized. |
701 | */ | 701 | */ |
702 | static const struct token keywords[] = { | 702 | static const struct token keywords[] = { |
703 | {"menu", T_MENU}, | 703 | {"menu", T_MENU}, |
704 | {"title", T_TITLE}, | 704 | {"title", T_TITLE}, |
705 | {"timeout", T_TIMEOUT}, | 705 | {"timeout", T_TIMEOUT}, |
706 | {"default", T_DEFAULT}, | 706 | {"default", T_DEFAULT}, |
707 | {"prompt", T_PROMPT}, | 707 | {"prompt", T_PROMPT}, |
708 | {"label", T_LABEL}, | 708 | {"label", T_LABEL}, |
709 | {"kernel", T_KERNEL}, | 709 | {"kernel", T_KERNEL}, |
710 | {"linux", T_LINUX}, | 710 | {"linux", T_LINUX}, |
711 | {"localboot", T_LOCALBOOT}, | 711 | {"localboot", T_LOCALBOOT}, |
712 | {"append", T_APPEND}, | 712 | {"append", T_APPEND}, |
713 | {"initrd", T_INITRD}, | 713 | {"initrd", T_INITRD}, |
714 | {"include", T_INCLUDE}, | 714 | {"include", T_INCLUDE}, |
715 | {"fdt", T_FDT}, | 715 | {"fdt", T_FDT}, |
716 | {NULL, T_INVALID} | 716 | {NULL, T_INVALID} |
717 | }; | 717 | }; |
718 | 718 | ||
719 | /* | 719 | /* |
720 | * Since pxe(linux) files don't have a token to identify the start of a | 720 | * Since pxe(linux) files don't have a token to identify the start of a |
721 | * literal, we have to keep track of when we're in a state where a literal is | 721 | * literal, we have to keep track of when we're in a state where a literal is |
722 | * expected vs when we're in a state a keyword is expected. | 722 | * expected vs when we're in a state a keyword is expected. |
723 | */ | 723 | */ |
724 | enum lex_state { | 724 | enum lex_state { |
725 | L_NORMAL = 0, | 725 | L_NORMAL = 0, |
726 | L_KEYWORD, | 726 | L_KEYWORD, |
727 | L_SLITERAL | 727 | L_SLITERAL |
728 | }; | 728 | }; |
729 | 729 | ||
730 | /* | 730 | /* |
731 | * get_string retrieves a string from *p and stores it as a token in | 731 | * get_string retrieves a string from *p and stores it as a token in |
732 | * *t. | 732 | * *t. |
733 | * | 733 | * |
734 | * get_string used for scanning both string literals and keywords. | 734 | * get_string used for scanning both string literals and keywords. |
735 | * | 735 | * |
736 | * Characters from *p are copied into t-val until a character equal to | 736 | * Characters from *p are copied into t-val until a character equal to |
737 | * delim is found, or a NUL byte is reached. If delim has the special value of | 737 | * delim is found, or a NUL byte is reached. If delim has the special value of |
738 | * ' ', any whitespace character will be used as a delimiter. | 738 | * ' ', any whitespace character will be used as a delimiter. |
739 | * | 739 | * |
740 | * If lower is unequal to 0, uppercase characters will be converted to | 740 | * If lower is unequal to 0, uppercase characters will be converted to |
741 | * lowercase in the result. This is useful to make keywords case | 741 | * lowercase in the result. This is useful to make keywords case |
742 | * insensitive. | 742 | * insensitive. |
743 | * | 743 | * |
744 | * The location of *p is updated to point to the first character after the end | 744 | * The location of *p is updated to point to the first character after the end |
745 | * of the token - the ending delimiter. | 745 | * of the token - the ending delimiter. |
746 | * | 746 | * |
747 | * On success, the new value of t->val is returned. Memory for t->val is | 747 | * On success, the new value of t->val is returned. Memory for t->val is |
748 | * allocated using malloc and must be free()'d to reclaim it. If insufficient | 748 | * allocated using malloc and must be free()'d to reclaim it. If insufficient |
749 | * memory is available, NULL is returned. | 749 | * memory is available, NULL is returned. |
750 | */ | 750 | */ |
751 | static char *get_string(char **p, struct token *t, char delim, int lower) | 751 | static char *get_string(char **p, struct token *t, char delim, int lower) |
752 | { | 752 | { |
753 | char *b, *e; | 753 | char *b, *e; |
754 | size_t len, i; | 754 | size_t len, i; |
755 | 755 | ||
756 | /* | 756 | /* |
757 | * b and e both start at the beginning of the input stream. | 757 | * b and e both start at the beginning of the input stream. |
758 | * | 758 | * |
759 | * e is incremented until we find the ending delimiter, or a NUL byte | 759 | * e is incremented until we find the ending delimiter, or a NUL byte |
760 | * is reached. Then, we take e - b to find the length of the token. | 760 | * is reached. Then, we take e - b to find the length of the token. |
761 | */ | 761 | */ |
762 | b = e = *p; | 762 | b = e = *p; |
763 | 763 | ||
764 | while (*e) { | 764 | while (*e) { |
765 | if ((delim == ' ' && isspace(*e)) || delim == *e) | 765 | if ((delim == ' ' && isspace(*e)) || delim == *e) |
766 | break; | 766 | break; |
767 | e++; | 767 | e++; |
768 | } | 768 | } |
769 | 769 | ||
770 | len = e - b; | 770 | len = e - b; |
771 | 771 | ||
772 | /* | 772 | /* |
773 | * Allocate memory to hold the string, and copy it in, converting | 773 | * Allocate memory to hold the string, and copy it in, converting |
774 | * characters to lowercase if lower is != 0. | 774 | * characters to lowercase if lower is != 0. |
775 | */ | 775 | */ |
776 | t->val = malloc(len + 1); | 776 | t->val = malloc(len + 1); |
777 | if (!t->val) | 777 | if (!t->val) |
778 | return NULL; | 778 | return NULL; |
779 | 779 | ||
780 | for (i = 0; i < len; i++, b++) { | 780 | for (i = 0; i < len; i++, b++) { |
781 | if (lower) | 781 | if (lower) |
782 | t->val[i] = tolower(*b); | 782 | t->val[i] = tolower(*b); |
783 | else | 783 | else |
784 | t->val[i] = *b; | 784 | t->val[i] = *b; |
785 | } | 785 | } |
786 | 786 | ||
787 | t->val[len] = '\0'; | 787 | t->val[len] = '\0'; |
788 | 788 | ||
789 | /* | 789 | /* |
790 | * Update *p so the caller knows where to continue scanning. | 790 | * Update *p so the caller knows where to continue scanning. |
791 | */ | 791 | */ |
792 | *p = e; | 792 | *p = e; |
793 | 793 | ||
794 | t->type = T_STRING; | 794 | t->type = T_STRING; |
795 | 795 | ||
796 | return t->val; | 796 | return t->val; |
797 | } | 797 | } |
798 | 798 | ||
799 | /* | 799 | /* |
800 | * Populate a keyword token with a type and value. | 800 | * Populate a keyword token with a type and value. |
801 | */ | 801 | */ |
802 | static void get_keyword(struct token *t) | 802 | static void get_keyword(struct token *t) |
803 | { | 803 | { |
804 | int i; | 804 | int i; |
805 | 805 | ||
806 | for (i = 0; keywords[i].val; i++) { | 806 | for (i = 0; keywords[i].val; i++) { |
807 | if (!strcmp(t->val, keywords[i].val)) { | 807 | if (!strcmp(t->val, keywords[i].val)) { |
808 | t->type = keywords[i].type; | 808 | t->type = keywords[i].type; |
809 | break; | 809 | break; |
810 | } | 810 | } |
811 | } | 811 | } |
812 | } | 812 | } |
813 | 813 | ||
814 | /* | 814 | /* |
815 | * Get the next token. We have to keep track of which state we're in to know | 815 | * Get the next token. We have to keep track of which state we're in to know |
816 | * if we're looking to get a string literal or a keyword. | 816 | * if we're looking to get a string literal or a keyword. |
817 | * | 817 | * |
818 | * *p is updated to point at the first character after the current token. | 818 | * *p is updated to point at the first character after the current token. |
819 | */ | 819 | */ |
820 | static void get_token(char **p, struct token *t, enum lex_state state) | 820 | static void get_token(char **p, struct token *t, enum lex_state state) |
821 | { | 821 | { |
822 | char *c = *p; | 822 | char *c = *p; |
823 | 823 | ||
824 | t->type = T_INVALID; | 824 | t->type = T_INVALID; |
825 | 825 | ||
826 | /* eat non EOL whitespace */ | 826 | /* eat non EOL whitespace */ |
827 | while (isblank(*c)) | 827 | while (isblank(*c)) |
828 | c++; | 828 | c++; |
829 | 829 | ||
830 | /* | 830 | /* |
831 | * eat comments. note that string literals can't begin with #, but | 831 | * eat comments. note that string literals can't begin with #, but |
832 | * can contain a # after their first character. | 832 | * can contain a # after their first character. |
833 | */ | 833 | */ |
834 | if (*c == '#') { | 834 | if (*c == '#') { |
835 | while (*c && *c != '\n') | 835 | while (*c && *c != '\n') |
836 | c++; | 836 | c++; |
837 | } | 837 | } |
838 | 838 | ||
839 | if (*c == '\n') { | 839 | if (*c == '\n') { |
840 | t->type = T_EOL; | 840 | t->type = T_EOL; |
841 | c++; | 841 | c++; |
842 | } else if (*c == '\0') { | 842 | } else if (*c == '\0') { |
843 | t->type = T_EOF; | 843 | t->type = T_EOF; |
844 | c++; | 844 | c++; |
845 | } else if (state == L_SLITERAL) { | 845 | } else if (state == L_SLITERAL) { |
846 | get_string(&c, t, '\n', 0); | 846 | get_string(&c, t, '\n', 0); |
847 | } else if (state == L_KEYWORD) { | 847 | } else if (state == L_KEYWORD) { |
848 | /* | 848 | /* |
849 | * when we expect a keyword, we first get the next string | 849 | * when we expect a keyword, we first get the next string |
850 | * token delimited by whitespace, and then check if it | 850 | * token delimited by whitespace, and then check if it |
851 | * matches a keyword in our keyword list. if it does, it's | 851 | * matches a keyword in our keyword list. if it does, it's |
852 | * converted to a keyword token of the appropriate type, and | 852 | * converted to a keyword token of the appropriate type, and |
853 | * if not, it remains a string token. | 853 | * if not, it remains a string token. |
854 | */ | 854 | */ |
855 | get_string(&c, t, ' ', 1); | 855 | get_string(&c, t, ' ', 1); |
856 | get_keyword(t); | 856 | get_keyword(t); |
857 | } | 857 | } |
858 | 858 | ||
859 | *p = c; | 859 | *p = c; |
860 | } | 860 | } |
861 | 861 | ||
862 | /* | 862 | /* |
863 | * Increment *c until we get to the end of the current line, or EOF. | 863 | * Increment *c until we get to the end of the current line, or EOF. |
864 | */ | 864 | */ |
865 | static void eol_or_eof(char **c) | 865 | static void eol_or_eof(char **c) |
866 | { | 866 | { |
867 | while (**c && **c != '\n') | 867 | while (**c && **c != '\n') |
868 | (*c)++; | 868 | (*c)++; |
869 | } | 869 | } |
870 | 870 | ||
871 | /* | 871 | /* |
872 | * All of these parse_* functions share some common behavior. | 872 | * All of these parse_* functions share some common behavior. |
873 | * | 873 | * |
874 | * They finish with *c pointing after the token they parse, and return 1 on | 874 | * They finish with *c pointing after the token they parse, and return 1 on |
875 | * success, or < 0 on error. | 875 | * success, or < 0 on error. |
876 | */ | 876 | */ |
877 | 877 | ||
878 | /* | 878 | /* |
879 | * Parse a string literal and store a pointer it at *dst. String literals | 879 | * Parse a string literal and store a pointer it at *dst. String literals |
880 | * terminate at the end of the line. | 880 | * terminate at the end of the line. |
881 | */ | 881 | */ |
882 | static int parse_sliteral(char **c, char **dst) | 882 | static int parse_sliteral(char **c, char **dst) |
883 | { | 883 | { |
884 | struct token t; | 884 | struct token t; |
885 | char *s = *c; | 885 | char *s = *c; |
886 | 886 | ||
887 | get_token(c, &t, L_SLITERAL); | 887 | get_token(c, &t, L_SLITERAL); |
888 | 888 | ||
889 | if (t.type != T_STRING) { | 889 | if (t.type != T_STRING) { |
890 | printf("Expected string literal: %.*s\n", (int)(*c - s), s); | 890 | printf("Expected string literal: %.*s\n", (int)(*c - s), s); |
891 | return -EINVAL; | 891 | return -EINVAL; |
892 | } | 892 | } |
893 | 893 | ||
894 | *dst = t.val; | 894 | *dst = t.val; |
895 | 895 | ||
896 | return 1; | 896 | return 1; |
897 | } | 897 | } |
898 | 898 | ||
899 | /* | 899 | /* |
900 | * Parse a base 10 (unsigned) integer and store it at *dst. | 900 | * Parse a base 10 (unsigned) integer and store it at *dst. |
901 | */ | 901 | */ |
902 | static int parse_integer(char **c, int *dst) | 902 | static int parse_integer(char **c, int *dst) |
903 | { | 903 | { |
904 | struct token t; | 904 | struct token t; |
905 | char *s = *c; | 905 | char *s = *c; |
906 | unsigned long temp; | 906 | unsigned long temp; |
907 | 907 | ||
908 | get_token(c, &t, L_SLITERAL); | 908 | get_token(c, &t, L_SLITERAL); |
909 | 909 | ||
910 | if (t.type != T_STRING) { | 910 | if (t.type != T_STRING) { |
911 | printf("Expected string: %.*s\n", (int)(*c - s), s); | 911 | printf("Expected string: %.*s\n", (int)(*c - s), s); |
912 | return -EINVAL; | 912 | return -EINVAL; |
913 | } | 913 | } |
914 | 914 | ||
915 | if (strict_strtoul(t.val, 10, &temp) < 0) { | 915 | if (strict_strtoul(t.val, 10, &temp) < 0) { |
916 | printf("Expected unsigned integer: %s\n", t.val); | 916 | printf("Expected unsigned integer: %s\n", t.val); |
917 | return -EINVAL; | 917 | return -EINVAL; |
918 | } | 918 | } |
919 | 919 | ||
920 | *dst = (int)temp; | 920 | *dst = (int)temp; |
921 | 921 | ||
922 | free(t.val); | 922 | free(t.val); |
923 | 923 | ||
924 | return 1; | 924 | return 1; |
925 | } | 925 | } |
926 | 926 | ||
927 | static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level); | 927 | static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level); |
928 | 928 | ||
929 | /* | 929 | /* |
930 | * Parse an include statement, and retrieve and parse the file it mentions. | 930 | * Parse an include statement, and retrieve and parse the file it mentions. |
931 | * | 931 | * |
932 | * base should point to a location where it's safe to store the file, and | 932 | * base should point to a location where it's safe to store the file, and |
933 | * nest_level should indicate how many nested includes have occurred. For this | 933 | * nest_level should indicate how many nested includes have occurred. For this |
934 | * include, nest_level has already been incremented and doesn't need to be | 934 | * include, nest_level has already been incremented and doesn't need to be |
935 | * incremented here. | 935 | * incremented here. |
936 | */ | 936 | */ |
937 | static int handle_include(char **c, char *base, | 937 | static int handle_include(char **c, char *base, |
938 | struct pxe_menu *cfg, int nest_level) | 938 | struct pxe_menu *cfg, int nest_level) |
939 | { | 939 | { |
940 | char *include_path; | 940 | char *include_path; |
941 | char *s = *c; | 941 | char *s = *c; |
942 | int err; | 942 | int err; |
943 | 943 | ||
944 | err = parse_sliteral(c, &include_path); | 944 | err = parse_sliteral(c, &include_path); |
945 | 945 | ||
946 | if (err < 0) { | 946 | if (err < 0) { |
947 | printf("Expected include path: %.*s\n", | 947 | printf("Expected include path: %.*s\n", |
948 | (int)(*c - s), s); | 948 | (int)(*c - s), s); |
949 | return err; | 949 | return err; |
950 | } | 950 | } |
951 | 951 | ||
952 | err = get_pxe_file(include_path, base); | 952 | err = get_pxe_file(include_path, base); |
953 | 953 | ||
954 | if (err < 0) { | 954 | if (err < 0) { |
955 | printf("Couldn't retrieve %s\n", include_path); | 955 | printf("Couldn't retrieve %s\n", include_path); |
956 | return err; | 956 | return err; |
957 | } | 957 | } |
958 | 958 | ||
959 | return parse_pxefile_top(base, cfg, nest_level); | 959 | return parse_pxefile_top(base, cfg, nest_level); |
960 | } | 960 | } |
961 | 961 | ||
962 | /* | 962 | /* |
963 | * Parse lines that begin with 'menu'. | 963 | * Parse lines that begin with 'menu'. |
964 | * | 964 | * |
965 | * b and nest are provided to handle the 'menu include' case. | 965 | * b and nest are provided to handle the 'menu include' case. |
966 | * | 966 | * |
967 | * b should be the address where the file currently being parsed is stored. | 967 | * b should be the address where the file currently being parsed is stored. |
968 | * | 968 | * |
969 | * nest_level should be 1 when parsing the top level pxe file, 2 when parsing | 969 | * nest_level should be 1 when parsing the top level pxe file, 2 when parsing |
970 | * a file it includes, 3 when parsing a file included by that file, and so on. | 970 | * a file it includes, 3 when parsing a file included by that file, and so on. |
971 | */ | 971 | */ |
972 | static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level) | 972 | static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level) |
973 | { | 973 | { |
974 | struct token t; | 974 | struct token t; |
975 | char *s = *c; | 975 | char *s = *c; |
976 | int err = 0; | 976 | int err = 0; |
977 | 977 | ||
978 | get_token(c, &t, L_KEYWORD); | 978 | get_token(c, &t, L_KEYWORD); |
979 | 979 | ||
980 | switch (t.type) { | 980 | switch (t.type) { |
981 | case T_TITLE: | 981 | case T_TITLE: |
982 | err = parse_sliteral(c, &cfg->title); | 982 | err = parse_sliteral(c, &cfg->title); |
983 | 983 | ||
984 | break; | 984 | break; |
985 | 985 | ||
986 | case T_INCLUDE: | 986 | case T_INCLUDE: |
987 | err = handle_include(c, b + strlen(b) + 1, cfg, | 987 | err = handle_include(c, b + strlen(b) + 1, cfg, |
988 | nest_level + 1); | 988 | nest_level + 1); |
989 | break; | 989 | break; |
990 | 990 | ||
991 | default: | 991 | default: |
992 | printf("Ignoring malformed menu command: %.*s\n", | 992 | printf("Ignoring malformed menu command: %.*s\n", |
993 | (int)(*c - s), s); | 993 | (int)(*c - s), s); |
994 | } | 994 | } |
995 | 995 | ||
996 | if (err < 0) | 996 | if (err < 0) |
997 | return err; | 997 | return err; |
998 | 998 | ||
999 | eol_or_eof(c); | 999 | eol_or_eof(c); |
1000 | 1000 | ||
1001 | return 1; | 1001 | return 1; |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | /* | 1004 | /* |
1005 | * Handles parsing a 'menu line' when we're parsing a label. | 1005 | * Handles parsing a 'menu line' when we're parsing a label. |
1006 | */ | 1006 | */ |
1007 | static int parse_label_menu(char **c, struct pxe_menu *cfg, | 1007 | static int parse_label_menu(char **c, struct pxe_menu *cfg, |
1008 | struct pxe_label *label) | 1008 | struct pxe_label *label) |
1009 | { | 1009 | { |
1010 | struct token t; | 1010 | struct token t; |
1011 | char *s; | 1011 | char *s; |
1012 | 1012 | ||
1013 | s = *c; | 1013 | s = *c; |
1014 | 1014 | ||
1015 | get_token(c, &t, L_KEYWORD); | 1015 | get_token(c, &t, L_KEYWORD); |
1016 | 1016 | ||
1017 | switch (t.type) { | 1017 | switch (t.type) { |
1018 | case T_DEFAULT: | 1018 | case T_DEFAULT: |
1019 | if (cfg->default_label) | 1019 | if (cfg->default_label) |
1020 | free(cfg->default_label); | 1020 | free(cfg->default_label); |
1021 | 1021 | ||
1022 | cfg->default_label = strdup(label->name); | 1022 | cfg->default_label = strdup(label->name); |
1023 | 1023 | ||
1024 | if (!cfg->default_label) | 1024 | if (!cfg->default_label) |
1025 | return -ENOMEM; | 1025 | return -ENOMEM; |
1026 | 1026 | ||
1027 | break; | 1027 | break; |
1028 | case T_LABEL: | 1028 | case T_LABEL: |
1029 | parse_sliteral(c, &label->menu); | 1029 | parse_sliteral(c, &label->menu); |
1030 | break; | 1030 | break; |
1031 | default: | 1031 | default: |
1032 | printf("Ignoring malformed menu command: %.*s\n", | 1032 | printf("Ignoring malformed menu command: %.*s\n", |
1033 | (int)(*c - s), s); | 1033 | (int)(*c - s), s); |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | eol_or_eof(c); | 1036 | eol_or_eof(c); |
1037 | 1037 | ||
1038 | return 0; | 1038 | return 0; |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | /* | 1041 | /* |
1042 | * Parses a label and adds it to the list of labels for a menu. | 1042 | * Parses a label and adds it to the list of labels for a menu. |
1043 | * | 1043 | * |
1044 | * A label ends when we either get to the end of a file, or | 1044 | * A label ends when we either get to the end of a file, or |
1045 | * get some input we otherwise don't have a handler defined | 1045 | * get some input we otherwise don't have a handler defined |
1046 | * for. | 1046 | * for. |
1047 | * | 1047 | * |
1048 | */ | 1048 | */ |
1049 | static int parse_label(char **c, struct pxe_menu *cfg) | 1049 | static int parse_label(char **c, struct pxe_menu *cfg) |
1050 | { | 1050 | { |
1051 | struct token t; | 1051 | struct token t; |
1052 | int len; | 1052 | int len; |
1053 | char *s = *c; | 1053 | char *s = *c; |
1054 | struct pxe_label *label; | 1054 | struct pxe_label *label; |
1055 | int err; | 1055 | int err; |
1056 | 1056 | ||
1057 | label = label_create(); | 1057 | label = label_create(); |
1058 | if (!label) | 1058 | if (!label) |
1059 | return -ENOMEM; | 1059 | return -ENOMEM; |
1060 | 1060 | ||
1061 | err = parse_sliteral(c, &label->name); | 1061 | err = parse_sliteral(c, &label->name); |
1062 | if (err < 0) { | 1062 | if (err < 0) { |
1063 | printf("Expected label name: %.*s\n", (int)(*c - s), s); | 1063 | printf("Expected label name: %.*s\n", (int)(*c - s), s); |
1064 | label_destroy(label); | 1064 | label_destroy(label); |
1065 | return -EINVAL; | 1065 | return -EINVAL; |
1066 | } | 1066 | } |
1067 | 1067 | ||
1068 | list_add_tail(&label->list, &cfg->labels); | 1068 | list_add_tail(&label->list, &cfg->labels); |
1069 | 1069 | ||
1070 | while (1) { | 1070 | while (1) { |
1071 | s = *c; | 1071 | s = *c; |
1072 | get_token(c, &t, L_KEYWORD); | 1072 | get_token(c, &t, L_KEYWORD); |
1073 | 1073 | ||
1074 | err = 0; | 1074 | err = 0; |
1075 | switch (t.type) { | 1075 | switch (t.type) { |
1076 | case T_MENU: | 1076 | case T_MENU: |
1077 | err = parse_label_menu(c, cfg, label); | 1077 | err = parse_label_menu(c, cfg, label); |
1078 | break; | 1078 | break; |
1079 | 1079 | ||
1080 | case T_KERNEL: | 1080 | case T_KERNEL: |
1081 | case T_LINUX: | 1081 | case T_LINUX: |
1082 | err = parse_sliteral(c, &label->kernel); | 1082 | err = parse_sliteral(c, &label->kernel); |
1083 | break; | 1083 | break; |
1084 | 1084 | ||
1085 | case T_APPEND: | 1085 | case T_APPEND: |
1086 | err = parse_sliteral(c, &label->append); | 1086 | err = parse_sliteral(c, &label->append); |
1087 | if (label->initrd) | 1087 | if (label->initrd) |
1088 | break; | 1088 | break; |
1089 | s = strstr(label->append, "initrd="); | 1089 | s = strstr(label->append, "initrd="); |
1090 | if (!s) | 1090 | if (!s) |
1091 | break; | 1091 | break; |
1092 | s += 7; | 1092 | s += 7; |
1093 | len = (int)(strchr(s, ' ') - s); | 1093 | len = (int)(strchr(s, ' ') - s); |
1094 | label->initrd = malloc(len + 1); | 1094 | label->initrd = malloc(len + 1); |
1095 | strncpy(label->initrd, s, len); | 1095 | strncpy(label->initrd, s, len); |
1096 | label->initrd[len] = '\0'; | 1096 | label->initrd[len] = '\0'; |
1097 | 1097 | ||
1098 | break; | 1098 | break; |
1099 | 1099 | ||
1100 | case T_INITRD: | 1100 | case T_INITRD: |
1101 | if (!label->initrd) | 1101 | if (!label->initrd) |
1102 | err = parse_sliteral(c, &label->initrd); | 1102 | err = parse_sliteral(c, &label->initrd); |
1103 | break; | 1103 | break; |
1104 | 1104 | ||
1105 | case T_FDT: | 1105 | case T_FDT: |
1106 | if (!label->fdt) | 1106 | if (!label->fdt) |
1107 | err = parse_sliteral(c, &label->fdt); | 1107 | err = parse_sliteral(c, &label->fdt); |
1108 | break; | 1108 | break; |
1109 | 1109 | ||
1110 | case T_LOCALBOOT: | 1110 | case T_LOCALBOOT: |
1111 | err = parse_integer(c, &label->localboot); | 1111 | err = parse_integer(c, &label->localboot); |
1112 | break; | 1112 | break; |
1113 | 1113 | ||
1114 | case T_EOL: | 1114 | case T_EOL: |
1115 | break; | 1115 | break; |
1116 | 1116 | ||
1117 | default: | 1117 | default: |
1118 | /* | 1118 | /* |
1119 | * put the token back! we don't want it - it's the end | 1119 | * put the token back! we don't want it - it's the end |
1120 | * of a label and whatever token this is, it's | 1120 | * of a label and whatever token this is, it's |
1121 | * something for the menu level context to handle. | 1121 | * something for the menu level context to handle. |
1122 | */ | 1122 | */ |
1123 | *c = s; | 1123 | *c = s; |
1124 | return 1; | 1124 | return 1; |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | if (err < 0) | 1127 | if (err < 0) |
1128 | return err; | 1128 | return err; |
1129 | } | 1129 | } |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | /* | 1132 | /* |
1133 | * This 16 comes from the limit pxelinux imposes on nested includes. | 1133 | * This 16 comes from the limit pxelinux imposes on nested includes. |
1134 | * | 1134 | * |
1135 | * There is no reason at all we couldn't do more, but some limit helps prevent | 1135 | * There is no reason at all we couldn't do more, but some limit helps prevent |
1136 | * infinite (until crash occurs) recursion if a file tries to include itself. | 1136 | * infinite (until crash occurs) recursion if a file tries to include itself. |
1137 | */ | 1137 | */ |
1138 | #define MAX_NEST_LEVEL 16 | 1138 | #define MAX_NEST_LEVEL 16 |
1139 | 1139 | ||
1140 | /* | 1140 | /* |
1141 | * Entry point for parsing a menu file. nest_level indicates how many times | 1141 | * Entry point for parsing a menu file. nest_level indicates how many times |
1142 | * we've nested in includes. It will be 1 for the top level menu file. | 1142 | * we've nested in includes. It will be 1 for the top level menu file. |
1143 | * | 1143 | * |
1144 | * Returns 1 on success, < 0 on error. | 1144 | * Returns 1 on success, < 0 on error. |
1145 | */ | 1145 | */ |
1146 | static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) | 1146 | static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) |
1147 | { | 1147 | { |
1148 | struct token t; | 1148 | struct token t; |
1149 | char *s, *b, *label_name; | 1149 | char *s, *b, *label_name; |
1150 | int err; | 1150 | int err; |
1151 | 1151 | ||
1152 | b = p; | 1152 | b = p; |
1153 | 1153 | ||
1154 | if (nest_level > MAX_NEST_LEVEL) { | 1154 | if (nest_level > MAX_NEST_LEVEL) { |
1155 | printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL); | 1155 | printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL); |
1156 | return -EMLINK; | 1156 | return -EMLINK; |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | while (1) { | 1159 | while (1) { |
1160 | s = p; | 1160 | s = p; |
1161 | 1161 | ||
1162 | get_token(&p, &t, L_KEYWORD); | 1162 | get_token(&p, &t, L_KEYWORD); |
1163 | 1163 | ||
1164 | err = 0; | 1164 | err = 0; |
1165 | switch (t.type) { | 1165 | switch (t.type) { |
1166 | case T_MENU: | 1166 | case T_MENU: |
1167 | err = parse_menu(&p, cfg, b, nest_level); | 1167 | err = parse_menu(&p, cfg, b, nest_level); |
1168 | break; | 1168 | break; |
1169 | 1169 | ||
1170 | case T_TIMEOUT: | 1170 | case T_TIMEOUT: |
1171 | err = parse_integer(&p, &cfg->timeout); | 1171 | err = parse_integer(&p, &cfg->timeout); |
1172 | break; | 1172 | break; |
1173 | 1173 | ||
1174 | case T_LABEL: | 1174 | case T_LABEL: |
1175 | err = parse_label(&p, cfg); | 1175 | err = parse_label(&p, cfg); |
1176 | break; | 1176 | break; |
1177 | 1177 | ||
1178 | case T_DEFAULT: | 1178 | case T_DEFAULT: |
1179 | err = parse_sliteral(&p, &label_name); | 1179 | err = parse_sliteral(&p, &label_name); |
1180 | 1180 | ||
1181 | if (label_name) { | 1181 | if (label_name) { |
1182 | if (cfg->default_label) | 1182 | if (cfg->default_label) |
1183 | free(cfg->default_label); | 1183 | free(cfg->default_label); |
1184 | 1184 | ||
1185 | cfg->default_label = label_name; | 1185 | cfg->default_label = label_name; |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | break; | 1188 | break; |
1189 | 1189 | ||
1190 | case T_INCLUDE: | 1190 | case T_INCLUDE: |
1191 | err = handle_include(&p, b + ALIGN(strlen(b), 4), cfg, | 1191 | err = handle_include(&p, b + ALIGN(strlen(b), 4), cfg, |
1192 | nest_level + 1); | 1192 | nest_level + 1); |
1193 | break; | 1193 | break; |
1194 | 1194 | ||
1195 | case T_PROMPT: | 1195 | case T_PROMPT: |
1196 | err = parse_integer(&p, &cfg->prompt); | 1196 | err = parse_integer(&p, &cfg->prompt); |
1197 | break; | 1197 | break; |
1198 | 1198 | ||
1199 | case T_EOL: | 1199 | case T_EOL: |
1200 | break; | 1200 | break; |
1201 | 1201 | ||
1202 | case T_EOF: | 1202 | case T_EOF: |
1203 | return 1; | 1203 | return 1; |
1204 | 1204 | ||
1205 | default: | 1205 | default: |
1206 | printf("Ignoring unknown command: %.*s\n", | 1206 | printf("Ignoring unknown command: %.*s\n", |
1207 | (int)(p - s), s); | 1207 | (int)(p - s), s); |
1208 | eol_or_eof(&p); | 1208 | eol_or_eof(&p); |
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | if (err < 0) | 1211 | if (err < 0) |
1212 | return err; | 1212 | return err; |
1213 | } | 1213 | } |
1214 | } | 1214 | } |
1215 | 1215 | ||
1216 | /* | 1216 | /* |
1217 | * Free the memory used by a pxe_menu and its labels. | 1217 | * Free the memory used by a pxe_menu and its labels. |
1218 | */ | 1218 | */ |
1219 | static void destroy_pxe_menu(struct pxe_menu *cfg) | 1219 | static void destroy_pxe_menu(struct pxe_menu *cfg) |
1220 | { | 1220 | { |
1221 | struct list_head *pos, *n; | 1221 | struct list_head *pos, *n; |
1222 | struct pxe_label *label; | 1222 | struct pxe_label *label; |
1223 | 1223 | ||
1224 | if (cfg->title) | 1224 | if (cfg->title) |
1225 | free(cfg->title); | 1225 | free(cfg->title); |
1226 | 1226 | ||
1227 | if (cfg->default_label) | 1227 | if (cfg->default_label) |
1228 | free(cfg->default_label); | 1228 | free(cfg->default_label); |
1229 | 1229 | ||
1230 | list_for_each_safe(pos, n, &cfg->labels) { | 1230 | list_for_each_safe(pos, n, &cfg->labels) { |
1231 | label = list_entry(pos, struct pxe_label, list); | 1231 | label = list_entry(pos, struct pxe_label, list); |
1232 | 1232 | ||
1233 | label_destroy(label); | 1233 | label_destroy(label); |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | free(cfg); | 1236 | free(cfg); |
1237 | } | 1237 | } |
1238 | 1238 | ||
1239 | /* | 1239 | /* |
1240 | * Entry point for parsing a pxe file. This is only used for the top level | 1240 | * Entry point for parsing a pxe file. This is only used for the top level |
1241 | * file. | 1241 | * file. |
1242 | * | 1242 | * |
1243 | * Returns NULL if there is an error, otherwise, returns a pointer to a | 1243 | * Returns NULL if there is an error, otherwise, returns a pointer to a |
1244 | * pxe_menu struct populated with the results of parsing the pxe file (and any | 1244 | * pxe_menu struct populated with the results of parsing the pxe file (and any |
1245 | * files it includes). The resulting pxe_menu struct can be free()'d by using | 1245 | * files it includes). The resulting pxe_menu struct can be free()'d by using |
1246 | * the destroy_pxe_menu() function. | 1246 | * the destroy_pxe_menu() function. |
1247 | */ | 1247 | */ |
1248 | static struct pxe_menu *parse_pxefile(char *menucfg) | 1248 | static struct pxe_menu *parse_pxefile(char *menucfg) |
1249 | { | 1249 | { |
1250 | struct pxe_menu *cfg; | 1250 | struct pxe_menu *cfg; |
1251 | 1251 | ||
1252 | cfg = malloc(sizeof(struct pxe_menu)); | 1252 | cfg = malloc(sizeof(struct pxe_menu)); |
1253 | 1253 | ||
1254 | if (!cfg) | 1254 | if (!cfg) |
1255 | return NULL; | 1255 | return NULL; |
1256 | 1256 | ||
1257 | memset(cfg, 0, sizeof(struct pxe_menu)); | 1257 | memset(cfg, 0, sizeof(struct pxe_menu)); |
1258 | 1258 | ||
1259 | INIT_LIST_HEAD(&cfg->labels); | 1259 | INIT_LIST_HEAD(&cfg->labels); |
1260 | 1260 | ||
1261 | if (parse_pxefile_top(menucfg, cfg, 1) < 0) { | 1261 | if (parse_pxefile_top(menucfg, cfg, 1) < 0) { |
1262 | destroy_pxe_menu(cfg); | 1262 | destroy_pxe_menu(cfg); |
1263 | return NULL; | 1263 | return NULL; |
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | return cfg; | 1266 | return cfg; |
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | /* | 1269 | /* |
1270 | * Converts a pxe_menu struct into a menu struct for use with U-boot's generic | 1270 | * Converts a pxe_menu struct into a menu struct for use with U-boot's generic |
1271 | * menu code. | 1271 | * menu code. |
1272 | */ | 1272 | */ |
1273 | static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) | 1273 | static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) |
1274 | { | 1274 | { |
1275 | struct pxe_label *label; | 1275 | struct pxe_label *label; |
1276 | struct list_head *pos; | 1276 | struct list_head *pos; |
1277 | struct menu *m; | 1277 | struct menu *m; |
1278 | int err; | 1278 | int err; |
1279 | 1279 | ||
1280 | /* | 1280 | /* |
1281 | * Create a menu and add items for all the labels. | 1281 | * Create a menu and add items for all the labels. |
1282 | */ | 1282 | */ |
1283 | m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print); | 1283 | m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print, |
1284 | NULL, NULL); | ||
1284 | 1285 | ||
1285 | if (!m) | 1286 | if (!m) |
1286 | return NULL; | 1287 | return NULL; |
1287 | 1288 | ||
1288 | list_for_each(pos, &cfg->labels) { | 1289 | list_for_each(pos, &cfg->labels) { |
1289 | label = list_entry(pos, struct pxe_label, list); | 1290 | label = list_entry(pos, struct pxe_label, list); |
1290 | 1291 | ||
1291 | if (menu_item_add(m, label->name, label) != 1) { | 1292 | if (menu_item_add(m, label->name, label) != 1) { |
1292 | menu_destroy(m); | 1293 | menu_destroy(m); |
1293 | return NULL; | 1294 | return NULL; |
1294 | } | 1295 | } |
1295 | } | 1296 | } |
1296 | 1297 | ||
1297 | /* | 1298 | /* |
1298 | * After we've created items for each label in the menu, set the | 1299 | * After we've created items for each label in the menu, set the |
1299 | * menu's default label if one was specified. | 1300 | * menu's default label if one was specified. |
1300 | */ | 1301 | */ |
1301 | if (cfg->default_label) { | 1302 | if (cfg->default_label) { |
1302 | err = menu_default_set(m, cfg->default_label); | 1303 | err = menu_default_set(m, cfg->default_label); |
1303 | if (err != 1) { | 1304 | if (err != 1) { |
1304 | if (err != -ENOENT) { | 1305 | if (err != -ENOENT) { |
1305 | menu_destroy(m); | 1306 | menu_destroy(m); |
1306 | return NULL; | 1307 | return NULL; |
1307 | } | 1308 | } |
1308 | 1309 | ||
1309 | printf("Missing default: %s\n", cfg->default_label); | 1310 | printf("Missing default: %s\n", cfg->default_label); |
1310 | } | 1311 | } |
1311 | } | 1312 | } |
1312 | 1313 | ||
1313 | return m; | 1314 | return m; |
1314 | } | 1315 | } |
1315 | 1316 | ||
1316 | /* | 1317 | /* |
1317 | * Try to boot any labels we have yet to attempt to boot. | 1318 | * Try to boot any labels we have yet to attempt to boot. |
1318 | */ | 1319 | */ |
1319 | static void boot_unattempted_labels(struct pxe_menu *cfg) | 1320 | static void boot_unattempted_labels(struct pxe_menu *cfg) |
1320 | { | 1321 | { |
1321 | struct list_head *pos; | 1322 | struct list_head *pos; |
1322 | struct pxe_label *label; | 1323 | struct pxe_label *label; |
1323 | 1324 | ||
1324 | list_for_each(pos, &cfg->labels) { | 1325 | list_for_each(pos, &cfg->labels) { |
1325 | label = list_entry(pos, struct pxe_label, list); | 1326 | label = list_entry(pos, struct pxe_label, list); |
1326 | 1327 | ||
1327 | if (!label->attempted) | 1328 | if (!label->attempted) |
1328 | label_boot(label); | 1329 | label_boot(label); |
1329 | } | 1330 | } |
1330 | } | 1331 | } |
1331 | 1332 | ||
1332 | /* | 1333 | /* |
1333 | * Boot the system as prescribed by a pxe_menu. | 1334 | * Boot the system as prescribed by a pxe_menu. |
1334 | * | 1335 | * |
1335 | * Use the menu system to either get the user's choice or the default, based | 1336 | * Use the menu system to either get the user's choice or the default, based |
1336 | * on config or user input. If there is no default or user's choice, | 1337 | * on config or user input. If there is no default or user's choice, |
1337 | * attempted to boot labels in the order they were given in pxe files. | 1338 | * attempted to boot labels in the order they were given in pxe files. |
1338 | * If the default or user's choice fails to boot, attempt to boot other | 1339 | * If the default or user's choice fails to boot, attempt to boot other |
1339 | * labels in the order they were given in pxe files. | 1340 | * labels in the order they were given in pxe files. |
1340 | * | 1341 | * |
1341 | * If this function returns, there weren't any labels that successfully | 1342 | * If this function returns, there weren't any labels that successfully |
1342 | * booted, or the user interrupted the menu selection via ctrl+c. | 1343 | * booted, or the user interrupted the menu selection via ctrl+c. |
1343 | */ | 1344 | */ |
1344 | static void handle_pxe_menu(struct pxe_menu *cfg) | 1345 | static void handle_pxe_menu(struct pxe_menu *cfg) |
1345 | { | 1346 | { |
1346 | void *choice; | 1347 | void *choice; |
1347 | struct menu *m; | 1348 | struct menu *m; |
1348 | int err; | 1349 | int err; |
1349 | 1350 | ||
1350 | m = pxe_menu_to_menu(cfg); | 1351 | m = pxe_menu_to_menu(cfg); |
1351 | if (!m) | 1352 | if (!m) |
1352 | return; | 1353 | return; |
1353 | 1354 | ||
1354 | err = menu_get_choice(m, &choice); | 1355 | err = menu_get_choice(m, &choice); |
1355 | 1356 | ||
1356 | menu_destroy(m); | 1357 | menu_destroy(m); |
1357 | 1358 | ||
1358 | /* | 1359 | /* |
1359 | * err == 1 means we got a choice back from menu_get_choice. | 1360 | * err == 1 means we got a choice back from menu_get_choice. |
1360 | * | 1361 | * |
1361 | * err == -ENOENT if the menu was setup to select the default but no | 1362 | * err == -ENOENT if the menu was setup to select the default but no |
1362 | * default was set. in that case, we should continue trying to boot | 1363 | * default was set. in that case, we should continue trying to boot |
1363 | * labels that haven't been attempted yet. | 1364 | * labels that haven't been attempted yet. |
1364 | * | 1365 | * |
1365 | * otherwise, the user interrupted or there was some other error and | 1366 | * otherwise, the user interrupted or there was some other error and |
1366 | * we give up. | 1367 | * we give up. |
1367 | */ | 1368 | */ |
1368 | 1369 | ||
1369 | if (err == 1) | 1370 | if (err == 1) |
1370 | label_boot(choice); | 1371 | label_boot(choice); |
1371 | else if (err != -ENOENT) | 1372 | else if (err != -ENOENT) |
1372 | return; | 1373 | return; |
1373 | 1374 | ||
1374 | boot_unattempted_labels(cfg); | 1375 | boot_unattempted_labels(cfg); |
1375 | } | 1376 | } |
1376 | 1377 | ||
1377 | /* | 1378 | /* |
1378 | * Boots a system using a pxe file | 1379 | * Boots a system using a pxe file |
1379 | * | 1380 | * |
1380 | * Returns 0 on success, 1 on error. | 1381 | * Returns 0 on success, 1 on error. |
1381 | */ | 1382 | */ |
1382 | static int | 1383 | static int |
1383 | do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 1384 | do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
1384 | { | 1385 | { |
1385 | unsigned long pxefile_addr_r; | 1386 | unsigned long pxefile_addr_r; |
1386 | struct pxe_menu *cfg; | 1387 | struct pxe_menu *cfg; |
1387 | char *pxefile_addr_str; | 1388 | char *pxefile_addr_str; |
1388 | 1389 | ||
1389 | do_getfile = do_get_tftp; | 1390 | do_getfile = do_get_tftp; |
1390 | 1391 | ||
1391 | if (argc == 1) { | 1392 | if (argc == 1) { |
1392 | pxefile_addr_str = from_env("pxefile_addr_r"); | 1393 | pxefile_addr_str = from_env("pxefile_addr_r"); |
1393 | if (!pxefile_addr_str) | 1394 | if (!pxefile_addr_str) |
1394 | return 1; | 1395 | return 1; |
1395 | 1396 | ||
1396 | } else if (argc == 2) { | 1397 | } else if (argc == 2) { |
1397 | pxefile_addr_str = argv[1]; | 1398 | pxefile_addr_str = argv[1]; |
1398 | } else { | 1399 | } else { |
1399 | return CMD_RET_USAGE; | 1400 | return CMD_RET_USAGE; |
1400 | } | 1401 | } |
1401 | 1402 | ||
1402 | if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) { | 1403 | if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) { |
1403 | printf("Invalid pxefile address: %s\n", pxefile_addr_str); | 1404 | printf("Invalid pxefile address: %s\n", pxefile_addr_str); |
1404 | return 1; | 1405 | return 1; |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | cfg = parse_pxefile((char *)(pxefile_addr_r)); | 1408 | cfg = parse_pxefile((char *)(pxefile_addr_r)); |
1408 | 1409 | ||
1409 | if (cfg == NULL) { | 1410 | if (cfg == NULL) { |
1410 | printf("Error parsing config file\n"); | 1411 | printf("Error parsing config file\n"); |
1411 | return 1; | 1412 | return 1; |
1412 | } | 1413 | } |
1413 | 1414 | ||
1414 | handle_pxe_menu(cfg); | 1415 | handle_pxe_menu(cfg); |
1415 | 1416 | ||
1416 | destroy_pxe_menu(cfg); | 1417 | destroy_pxe_menu(cfg); |
1417 | 1418 | ||
1418 | return 0; | 1419 | return 0; |
1419 | } | 1420 | } |
1420 | 1421 | ||
1421 | static cmd_tbl_t cmd_pxe_sub[] = { | 1422 | static cmd_tbl_t cmd_pxe_sub[] = { |
1422 | U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""), | 1423 | U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""), |
1423 | U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "") | 1424 | U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "") |
1424 | }; | 1425 | }; |
1425 | 1426 | ||
1426 | int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 1427 | int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
1427 | { | 1428 | { |
1428 | cmd_tbl_t *cp; | 1429 | cmd_tbl_t *cp; |
1429 | 1430 | ||
1430 | if (argc < 2) | 1431 | if (argc < 2) |
1431 | return CMD_RET_USAGE; | 1432 | return CMD_RET_USAGE; |
1432 | 1433 | ||
1433 | /* drop initial "pxe" arg */ | 1434 | /* drop initial "pxe" arg */ |
1434 | argc--; | 1435 | argc--; |
1435 | argv++; | 1436 | argv++; |
1436 | 1437 | ||
1437 | cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub)); | 1438 | cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub)); |
1438 | 1439 | ||
1439 | if (cp) | 1440 | if (cp) |
1440 | return cp->cmd(cmdtp, flag, argc, argv); | 1441 | return cp->cmd(cmdtp, flag, argc, argv); |
1441 | 1442 | ||
1442 | return CMD_RET_USAGE; | 1443 | return CMD_RET_USAGE; |
1443 | } | 1444 | } |
1444 | 1445 | ||
1445 | U_BOOT_CMD( | 1446 | U_BOOT_CMD( |
1446 | pxe, 3, 1, do_pxe, | 1447 | pxe, 3, 1, do_pxe, |
1447 | "commands to get and boot from pxe files", | 1448 | "commands to get and boot from pxe files", |
1448 | "get - try to retrieve a pxe file using tftp\npxe " | 1449 | "get - try to retrieve a pxe file using tftp\npxe " |
1449 | "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n" | 1450 | "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n" |
1450 | ); | 1451 | ); |
1451 | 1452 | ||
1452 | /* | 1453 | /* |
1453 | * Boots a system using a local disk syslinux/extlinux file | 1454 | * Boots a system using a local disk syslinux/extlinux file |
1454 | * | 1455 | * |
1455 | * Returns 0 on success, 1 on error. | 1456 | * Returns 0 on success, 1 on error. |
1456 | */ | 1457 | */ |
1457 | int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 1458 | int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
1458 | { | 1459 | { |
1459 | unsigned long pxefile_addr_r; | 1460 | unsigned long pxefile_addr_r; |
1460 | struct pxe_menu *cfg; | 1461 | struct pxe_menu *cfg; |
1461 | char *pxefile_addr_str; | 1462 | char *pxefile_addr_str; |
1462 | char *filename; | 1463 | char *filename; |
1463 | int prompt = 0; | 1464 | int prompt = 0; |
1464 | 1465 | ||
1465 | if (strstr(argv[1], "-p")) { | 1466 | if (strstr(argv[1], "-p")) { |
1466 | prompt = 1; | 1467 | prompt = 1; |
1467 | argc--; | 1468 | argc--; |
1468 | argv++; | 1469 | argv++; |
1469 | } | 1470 | } |
1470 | 1471 | ||
1471 | if (argc < 4) | 1472 | if (argc < 4) |
1472 | return cmd_usage(cmdtp); | 1473 | return cmd_usage(cmdtp); |
1473 | 1474 | ||
1474 | if (argc < 5) { | 1475 | if (argc < 5) { |
1475 | pxefile_addr_str = from_env("pxefile_addr_r"); | 1476 | pxefile_addr_str = from_env("pxefile_addr_r"); |
1476 | if (!pxefile_addr_str) | 1477 | if (!pxefile_addr_str) |
1477 | return 1; | 1478 | return 1; |
1478 | } else { | 1479 | } else { |
1479 | pxefile_addr_str = argv[4]; | 1480 | pxefile_addr_str = argv[4]; |
1480 | } | 1481 | } |
1481 | 1482 | ||
1482 | if (argc < 6) | 1483 | if (argc < 6) |
1483 | filename = getenv("bootfile"); | 1484 | filename = getenv("bootfile"); |
1484 | else { | 1485 | else { |
1485 | filename = argv[5]; | 1486 | filename = argv[5]; |
1486 | setenv("bootfile", filename); | 1487 | setenv("bootfile", filename); |
1487 | } | 1488 | } |
1488 | 1489 | ||
1489 | if (strstr(argv[3], "ext2")) | 1490 | if (strstr(argv[3], "ext2")) |
1490 | do_getfile = do_get_ext2; | 1491 | do_getfile = do_get_ext2; |
1491 | else if (strstr(argv[3], "fat")) | 1492 | else if (strstr(argv[3], "fat")) |
1492 | do_getfile = do_get_fat; | 1493 | do_getfile = do_get_fat; |
1493 | else { | 1494 | else { |
1494 | printf("Invalid filesystem: %s\n", argv[3]); | 1495 | printf("Invalid filesystem: %s\n", argv[3]); |
1495 | return 1; | 1496 | return 1; |
1496 | } | 1497 | } |
1497 | fs_argv[1] = argv[1]; | 1498 | fs_argv[1] = argv[1]; |
1498 | fs_argv[2] = argv[2]; | 1499 | fs_argv[2] = argv[2]; |
1499 | 1500 | ||
1500 | if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) { | 1501 | if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) { |
1501 | printf("Invalid pxefile address: %s\n", pxefile_addr_str); | 1502 | printf("Invalid pxefile address: %s\n", pxefile_addr_str); |
1502 | return 1; | 1503 | return 1; |
1503 | } | 1504 | } |
1504 | 1505 | ||
1505 | if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) { | 1506 | if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) { |
1506 | printf("Error reading config file\n"); | 1507 | printf("Error reading config file\n"); |
1507 | return 1; | 1508 | return 1; |
1508 | } | 1509 | } |
1509 | 1510 | ||
1510 | cfg = parse_pxefile((char *)(pxefile_addr_r)); | 1511 | cfg = parse_pxefile((char *)(pxefile_addr_r)); |
1511 | 1512 | ||
1512 | if (cfg == NULL) { | 1513 | if (cfg == NULL) { |
1513 | printf("Error parsing config file\n"); | 1514 | printf("Error parsing config file\n"); |
1514 | return 1; | 1515 | return 1; |
1515 | } | 1516 | } |
1516 | 1517 | ||
1517 | if (prompt) | 1518 | if (prompt) |
1518 | cfg->prompt = 1; | 1519 | cfg->prompt = 1; |
1519 | 1520 | ||
1520 | handle_pxe_menu(cfg); | 1521 | handle_pxe_menu(cfg); |
1521 | 1522 | ||
1522 | destroy_pxe_menu(cfg); | 1523 | destroy_pxe_menu(cfg); |
1523 | 1524 | ||
1524 | return 0; | 1525 | return 0; |
1525 | } | 1526 | } |
1526 | 1527 | ||
1527 | U_BOOT_CMD( | 1528 | U_BOOT_CMD( |
1528 | sysboot, 7, 1, do_sysboot, | 1529 | sysboot, 7, 1, do_sysboot, |
1529 | "command to get and boot from syslinux files", | 1530 | "command to get and boot from syslinux files", |
1530 | "[-p] <interface> <dev[:part]> <ext2|fat> [addr] [filename]\n" | 1531 | "[-p] <interface> <dev[:part]> <ext2|fat> [addr] [filename]\n" |
1531 | " - load and parse syslinux menu file 'filename' from ext2 or fat\n" | 1532 | " - load and parse syslinux menu file 'filename' from ext2 or fat\n" |
1532 | " filesystem on 'dev' on 'interface' to address 'addr'" | 1533 | " filesystem on 'dev' on 'interface' to address 'addr'" |
1533 | ); | 1534 | ); |
1534 | 1535 |
common/menu.c
1 | /* | 1 | /* |
2 | * Copyright 2010-2011 Calxeda, Inc. | 2 | * Copyright 2010-2011 Calxeda, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 5 | * under the terms of the GNU General Public License as published by the Free |
6 | * Software Foundation; either version 2 of the License, or (at your option) | 6 | * Software Foundation; either version 2 of the License, or (at your option) |
7 | * any later version. | 7 | * any later version. |
8 | * | 8 | * |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along with | 14 | * You should have received a copy of the GNU General Public License along with |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <common.h> | 18 | #include <common.h> |
19 | #include <malloc.h> | 19 | #include <malloc.h> |
20 | #include <errno.h> | 20 | #include <errno.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | 22 | ||
23 | #include "menu.h" | 23 | #include "menu.h" |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Internally, each item in a menu is represented by a struct menu_item. | 26 | * Internally, each item in a menu is represented by a struct menu_item. |
27 | * | 27 | * |
28 | * These items will be alloc'd and initialized by menu_item_add and destroyed | 28 | * These items will be alloc'd and initialized by menu_item_add and destroyed |
29 | * by menu_item_destroy, and the consumer of the interface never sees that | 29 | * by menu_item_destroy, and the consumer of the interface never sees that |
30 | * this struct is used at all. | 30 | * this struct is used at all. |
31 | */ | 31 | */ |
32 | struct menu_item { | 32 | struct menu_item { |
33 | char *key; | 33 | char *key; |
34 | void *data; | 34 | void *data; |
35 | struct list_head list; | 35 | struct list_head list; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * The menu is composed of a list of items along with settings and callbacks | 39 | * The menu is composed of a list of items along with settings and callbacks |
40 | * provided by the user. An incomplete definition of this struct is available | 40 | * provided by the user. An incomplete definition of this struct is available |
41 | * in menu.h, but the full definition is here to prevent consumers from | 41 | * in menu.h, but the full definition is here to prevent consumers from |
42 | * relying on its contents. | 42 | * relying on its contents. |
43 | */ | 43 | */ |
44 | struct menu { | 44 | struct menu { |
45 | struct menu_item *default_item; | 45 | struct menu_item *default_item; |
46 | int timeout; | 46 | int timeout; |
47 | char *title; | 47 | char *title; |
48 | int prompt; | 48 | int prompt; |
49 | void (*item_data_print)(void *); | 49 | void (*item_data_print)(void *); |
50 | char *(*item_choice)(void *); | ||
51 | void *item_choice_data; | ||
50 | struct list_head items; | 52 | struct list_head items; |
51 | }; | 53 | }; |
52 | 54 | ||
53 | /* | 55 | /* |
54 | * An iterator function for menu items. callback will be called for each item | 56 | * An iterator function for menu items. callback will be called for each item |
55 | * in m, with m, a pointer to the item, and extra being passed to callback. If | 57 | * in m, with m, a pointer to the item, and extra being passed to callback. If |
56 | * callback returns a value other than NULL, iteration stops and the value | 58 | * callback returns a value other than NULL, iteration stops and the value |
57 | * return by callback is returned from menu_items_iter. This allows it to be | 59 | * return by callback is returned from menu_items_iter. This allows it to be |
58 | * used for search type operations. It is also safe for callback to remove the | 60 | * used for search type operations. It is also safe for callback to remove the |
59 | * item from the list of items. | 61 | * item from the list of items. |
60 | */ | 62 | */ |
61 | static inline void *menu_items_iter(struct menu *m, | 63 | static inline void *menu_items_iter(struct menu *m, |
62 | void *(*callback)(struct menu *, struct menu_item *, void *), | 64 | void *(*callback)(struct menu *, struct menu_item *, void *), |
63 | void *extra) | 65 | void *extra) |
64 | { | 66 | { |
65 | struct list_head *pos, *n; | 67 | struct list_head *pos, *n; |
66 | struct menu_item *item; | 68 | struct menu_item *item; |
67 | void *ret; | 69 | void *ret; |
68 | 70 | ||
69 | list_for_each_safe(pos, n, &m->items) { | 71 | list_for_each_safe(pos, n, &m->items) { |
70 | item = list_entry(pos, struct menu_item, list); | 72 | item = list_entry(pos, struct menu_item, list); |
71 | 73 | ||
72 | ret = callback(m, item, extra); | 74 | ret = callback(m, item, extra); |
73 | 75 | ||
74 | if (ret) | 76 | if (ret) |
75 | return ret; | 77 | return ret; |
76 | } | 78 | } |
77 | 79 | ||
78 | return NULL; | 80 | return NULL; |
79 | } | 81 | } |
80 | 82 | ||
81 | /* | 83 | /* |
82 | * Print a menu_item. If the consumer provided an item_data_print function | 84 | * Print a menu_item. If the consumer provided an item_data_print function |
83 | * when creating the menu, call it with a pointer to the item's private data. | 85 | * when creating the menu, call it with a pointer to the item's private data. |
84 | * Otherwise, print the key of the item. | 86 | * Otherwise, print the key of the item. |
85 | */ | 87 | */ |
86 | static inline void *menu_item_print(struct menu *m, | 88 | static inline void *menu_item_print(struct menu *m, |
87 | struct menu_item *item, | 89 | struct menu_item *item, |
88 | void *extra) | 90 | void *extra) |
89 | { | 91 | { |
90 | if (!m->item_data_print) { | 92 | if (!m->item_data_print) { |
91 | puts(item->key); | 93 | puts(item->key); |
92 | putc('\n'); | 94 | putc('\n'); |
93 | } else { | 95 | } else { |
94 | m->item_data_print(item->data); | 96 | m->item_data_print(item->data); |
95 | } | 97 | } |
96 | 98 | ||
97 | return NULL; | 99 | return NULL; |
98 | } | 100 | } |
99 | 101 | ||
100 | /* | 102 | /* |
101 | * Free the memory used by a menu item. This includes the memory used by its | 103 | * Free the memory used by a menu item. This includes the memory used by its |
102 | * key. | 104 | * key. |
103 | */ | 105 | */ |
104 | static inline void *menu_item_destroy(struct menu *m, | 106 | static inline void *menu_item_destroy(struct menu *m, |
105 | struct menu_item *item, | 107 | struct menu_item *item, |
106 | void *extra) | 108 | void *extra) |
107 | { | 109 | { |
108 | if (item->key) | 110 | if (item->key) |
109 | free(item->key); | 111 | free(item->key); |
110 | 112 | ||
111 | free(item); | 113 | free(item); |
112 | 114 | ||
113 | return NULL; | 115 | return NULL; |
114 | } | 116 | } |
115 | 117 | ||
116 | void __menu_display_statusline(struct menu *m) | 118 | void __menu_display_statusline(struct menu *m) |
117 | { | 119 | { |
118 | return; | 120 | return; |
119 | } | 121 | } |
120 | void menu_display_statusline(struct menu *m) | 122 | void menu_display_statusline(struct menu *m) |
121 | __attribute__ ((weak, alias("__menu_display_statusline"))); | 123 | __attribute__ ((weak, alias("__menu_display_statusline"))); |
122 | 124 | ||
123 | /* | 125 | /* |
124 | * Display a menu so the user can make a choice of an item. First display its | 126 | * Display a menu so the user can make a choice of an item. First display its |
125 | * title, if any, and then each item in the menu. | 127 | * title, if any, and then each item in the menu. |
126 | */ | 128 | */ |
127 | static inline void menu_display(struct menu *m) | 129 | static inline void menu_display(struct menu *m) |
128 | { | 130 | { |
129 | if (m->title) { | 131 | if (m->title) { |
130 | puts(m->title); | 132 | puts(m->title); |
131 | putc('\n'); | 133 | putc('\n'); |
132 | } | 134 | } |
133 | menu_display_statusline(m); | 135 | menu_display_statusline(m); |
134 | 136 | ||
135 | menu_items_iter(m, menu_item_print, NULL); | 137 | menu_items_iter(m, menu_item_print, NULL); |
136 | } | 138 | } |
137 | 139 | ||
138 | /* | 140 | /* |
139 | * Check if an item's key matches a provided string, pointed to by extra. If | 141 | * Check if an item's key matches a provided string, pointed to by extra. If |
140 | * extra is NULL, an item with a NULL key will match. Otherwise, the item's | 142 | * extra is NULL, an item with a NULL key will match. Otherwise, the item's |
141 | * key has to match according to strcmp. | 143 | * key has to match according to strcmp. |
142 | * | 144 | * |
143 | * This is called via menu_items_iter, so it returns a pointer to the item if | 145 | * This is called via menu_items_iter, so it returns a pointer to the item if |
144 | * the key matches, and returns NULL otherwise. | 146 | * the key matches, and returns NULL otherwise. |
145 | */ | 147 | */ |
146 | static inline void *menu_item_key_match(struct menu *m, | 148 | static inline void *menu_item_key_match(struct menu *m, |
147 | struct menu_item *item, void *extra) | 149 | struct menu_item *item, void *extra) |
148 | { | 150 | { |
149 | char *item_key = extra; | 151 | char *item_key = extra; |
150 | 152 | ||
151 | if (!item_key || !item->key) { | 153 | if (!item_key || !item->key) { |
152 | if (item_key == item->key) | 154 | if (item_key == item->key) |
153 | return item; | 155 | return item; |
154 | 156 | ||
155 | return NULL; | 157 | return NULL; |
156 | } | 158 | } |
157 | 159 | ||
158 | if (strcmp(item->key, item_key) == 0) | 160 | if (strcmp(item->key, item_key) == 0) |
159 | return item; | 161 | return item; |
160 | 162 | ||
161 | return NULL; | 163 | return NULL; |
162 | } | 164 | } |
163 | 165 | ||
164 | /* | 166 | /* |
165 | * Find the first item with a key matching item_key, if any exists. | 167 | * Find the first item with a key matching item_key, if any exists. |
166 | */ | 168 | */ |
167 | static inline struct menu_item *menu_item_by_key(struct menu *m, | 169 | static inline struct menu_item *menu_item_by_key(struct menu *m, |
168 | char *item_key) | 170 | char *item_key) |
169 | { | 171 | { |
170 | return menu_items_iter(m, menu_item_key_match, item_key); | 172 | return menu_items_iter(m, menu_item_key_match, item_key); |
171 | } | 173 | } |
172 | 174 | ||
173 | /* | 175 | /* |
174 | * Set *choice to point to the default item's data, if any default item was | 176 | * Set *choice to point to the default item's data, if any default item was |
175 | * set, and returns 1. If no default item was set, returns -ENOENT. | 177 | * set, and returns 1. If no default item was set, returns -ENOENT. |
176 | */ | 178 | */ |
177 | static inline int menu_default_choice(struct menu *m, void **choice) | 179 | int menu_default_choice(struct menu *m, void **choice) |
178 | { | 180 | { |
179 | if (m->default_item) { | 181 | if (m->default_item) { |
180 | *choice = m->default_item->data; | 182 | *choice = m->default_item->data; |
181 | return 1; | 183 | return 1; |
182 | } | 184 | } |
183 | 185 | ||
184 | return -ENOENT; | 186 | return -ENOENT; |
185 | } | 187 | } |
186 | 188 | ||
187 | /* | 189 | /* |
188 | * Displays the menu and asks the user to choose an item. *choice will point | 190 | * Displays the menu and asks the user to choose an item. *choice will point |
189 | * to the private data of the item the user chooses. The user makes a choice | 191 | * to the private data of the item the user chooses. The user makes a choice |
190 | * by inputting a string matching the key of an item. Invalid choices will | 192 | * by inputting a string matching the key of an item. Invalid choices will |
191 | * cause the user to be prompted again, repeatedly, until the user makes a | 193 | * cause the user to be prompted again, repeatedly, until the user makes a |
192 | * valid choice. The user can exit the menu without making a choice via ^c. | 194 | * valid choice. The user can exit the menu without making a choice via ^c. |
193 | * | 195 | * |
194 | * Returns 1 if the user made a choice, or -EINTR if they bail via ^c. | 196 | * Returns 1 if the user made a choice, or -EINTR if they bail via ^c. |
195 | */ | 197 | */ |
196 | static inline int menu_interactive_choice(struct menu *m, void **choice) | 198 | static inline int menu_interactive_choice(struct menu *m, void **choice) |
197 | { | 199 | { |
198 | char cbuf[CONFIG_SYS_CBSIZE]; | 200 | char cbuf[CONFIG_SYS_CBSIZE]; |
199 | struct menu_item *choice_item = NULL; | 201 | struct menu_item *choice_item = NULL; |
200 | int readret; | 202 | int readret; |
201 | 203 | ||
202 | while (!choice_item) { | 204 | while (!choice_item) { |
203 | cbuf[0] = '\0'; | 205 | cbuf[0] = '\0'; |
204 | 206 | ||
205 | menu_display(m); | 207 | menu_display(m); |
206 | 208 | ||
207 | readret = readline_into_buffer("Enter choice: ", cbuf, | 209 | if (!m->item_choice) { |
208 | m->timeout / 10); | 210 | readret = readline_into_buffer("Enter choice: ", cbuf, |
211 | m->timeout / 10); | ||
209 | 212 | ||
210 | if (readret >= 0) { | 213 | if (readret >= 0) { |
211 | choice_item = menu_item_by_key(m, cbuf); | 214 | choice_item = menu_item_by_key(m, cbuf); |
212 | 215 | if (!choice_item) | |
213 | if (!choice_item) { | 216 | printf("%s not found\n", cbuf); |
214 | printf("%s not found\n", cbuf); | 217 | } else { |
215 | m->timeout = 0; | 218 | return menu_default_choice(m, choice); |
216 | } | 219 | } |
217 | } else | 220 | } else { |
218 | return menu_default_choice(m, choice); | 221 | char *key = m->item_choice(m->item_choice_data); |
222 | |||
223 | if (key) | ||
224 | choice_item = menu_item_by_key(m, key); | ||
225 | } | ||
226 | |||
227 | if (!choice_item) | ||
228 | m->timeout = 0; | ||
219 | } | 229 | } |
220 | 230 | ||
221 | *choice = choice_item->data; | 231 | *choice = choice_item->data; |
222 | 232 | ||
223 | return 1; | 233 | return 1; |
224 | } | 234 | } |
225 | 235 | ||
226 | /* | 236 | /* |
227 | * menu_default_set() - Sets the default choice for the menu. This is safe to | 237 | * menu_default_set() - Sets the default choice for the menu. This is safe to |
228 | * call more than once on a menu. | 238 | * call more than once on a menu. |
229 | * | 239 | * |
230 | * m - Points to a menu created by menu_create(). | 240 | * m - Points to a menu created by menu_create(). |
231 | * | 241 | * |
232 | * item_key - Points to a string that, when compared using strcmp, matches the | 242 | * item_key - Points to a string that, when compared using strcmp, matches the |
233 | * key for an existing item in the menu. | 243 | * key for an existing item in the menu. |
234 | * | 244 | * |
235 | * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a | 245 | * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a |
236 | * key matching item_key is found. | 246 | * key matching item_key is found. |
237 | */ | 247 | */ |
238 | int menu_default_set(struct menu *m, char *item_key) | 248 | int menu_default_set(struct menu *m, char *item_key) |
239 | { | 249 | { |
240 | struct menu_item *item; | 250 | struct menu_item *item; |
241 | 251 | ||
242 | if (!m) | 252 | if (!m) |
243 | return -EINVAL; | 253 | return -EINVAL; |
244 | 254 | ||
245 | item = menu_item_by_key(m, item_key); | 255 | item = menu_item_by_key(m, item_key); |
246 | 256 | ||
247 | if (!item) | 257 | if (!item) |
248 | return -ENOENT; | 258 | return -ENOENT; |
249 | 259 | ||
250 | m->default_item = item; | 260 | m->default_item = item; |
251 | 261 | ||
252 | return 1; | 262 | return 1; |
253 | } | 263 | } |
254 | 264 | ||
255 | /* | 265 | /* |
256 | * menu_get_choice() - Returns the user's selected menu entry, or the default | 266 | * menu_get_choice() - Returns the user's selected menu entry, or the default |
257 | * if the menu is set to not prompt or the timeout expires. This is safe to | 267 | * if the menu is set to not prompt or the timeout expires. This is safe to |
258 | * call more than once. | 268 | * call more than once. |
259 | * | 269 | * |
260 | * m - Points to a menu created by menu_create(). | 270 | * m - Points to a menu created by menu_create(). |
261 | * | 271 | * |
262 | * choice - Points to a location that will store a pointer to the selected | 272 | * choice - Points to a location that will store a pointer to the selected |
263 | * menu item. If no item is selected or there is an error, no value will be | 273 | * menu item. If no item is selected or there is an error, no value will be |
264 | * written at the location it points to. | 274 | * written at the location it points to. |
265 | * | 275 | * |
266 | * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no | 276 | * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no |
267 | * default has been set and the menu is set to not prompt or the timeout | 277 | * default has been set and the menu is set to not prompt or the timeout |
268 | * expires, or -EINTR if the user exits the menu via ^c. | 278 | * expires, or -EINTR if the user exits the menu via ^c. |
269 | */ | 279 | */ |
270 | int menu_get_choice(struct menu *m, void **choice) | 280 | int menu_get_choice(struct menu *m, void **choice) |
271 | { | 281 | { |
272 | if (!m || !choice) | 282 | if (!m || !choice) |
273 | return -EINVAL; | 283 | return -EINVAL; |
274 | 284 | ||
275 | if (!m->prompt) | 285 | if (!m->prompt) |
276 | return menu_default_choice(m, choice); | 286 | return menu_default_choice(m, choice); |
277 | 287 | ||
278 | return menu_interactive_choice(m, choice); | 288 | return menu_interactive_choice(m, choice); |
279 | } | 289 | } |
280 | 290 | ||
281 | /* | 291 | /* |
282 | * menu_item_add() - Adds or replaces a menu item. Note that this replaces the | 292 | * menu_item_add() - Adds or replaces a menu item. Note that this replaces the |
283 | * data of an item if it already exists, but doesn't change the order of the | 293 | * data of an item if it already exists, but doesn't change the order of the |
284 | * item. | 294 | * item. |
285 | * | 295 | * |
286 | * m - Points to a menu created by menu_create(). | 296 | * m - Points to a menu created by menu_create(). |
287 | * | 297 | * |
288 | * item_key - Points to a string that will uniquely identify the item. The | 298 | * item_key - Points to a string that will uniquely identify the item. The |
289 | * string will be copied to internal storage, and is safe to discard after | 299 | * string will be copied to internal storage, and is safe to discard after |
290 | * passing to menu_item_add. | 300 | * passing to menu_item_add. |
291 | * | 301 | * |
292 | * item_data - An opaque pointer associated with an item. It is never | 302 | * item_data - An opaque pointer associated with an item. It is never |
293 | * dereferenced internally, but will be passed to the item_data_print, and | 303 | * dereferenced internally, but will be passed to the item_data_print, and |
294 | * will be returned from menu_get_choice if the menu item is selected. | 304 | * will be returned from menu_get_choice if the menu item is selected. |
295 | * | 305 | * |
296 | * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is | 306 | * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is |
297 | * insufficient memory to add the menu item. | 307 | * insufficient memory to add the menu item. |
298 | */ | 308 | */ |
299 | int menu_item_add(struct menu *m, char *item_key, void *item_data) | 309 | int menu_item_add(struct menu *m, char *item_key, void *item_data) |
300 | { | 310 | { |
301 | struct menu_item *item; | 311 | struct menu_item *item; |
302 | 312 | ||
303 | if (!m) | 313 | if (!m) |
304 | return -EINVAL; | 314 | return -EINVAL; |
305 | 315 | ||
306 | item = menu_item_by_key(m, item_key); | 316 | item = menu_item_by_key(m, item_key); |
307 | 317 | ||
308 | if (item) { | 318 | if (item) { |
309 | item->data = item_data; | 319 | item->data = item_data; |
310 | return 1; | 320 | return 1; |
311 | } | 321 | } |
312 | 322 | ||
313 | item = malloc(sizeof *item); | 323 | item = malloc(sizeof *item); |
314 | if (!item) | 324 | if (!item) |
315 | return -ENOMEM; | 325 | return -ENOMEM; |
316 | 326 | ||
317 | item->key = strdup(item_key); | 327 | item->key = strdup(item_key); |
318 | 328 | ||
319 | if (!item->key) { | 329 | if (!item->key) { |
320 | free(item); | 330 | free(item); |
321 | return -ENOMEM; | 331 | return -ENOMEM; |
322 | } | 332 | } |
323 | 333 | ||
324 | item->data = item_data; | 334 | item->data = item_data; |
325 | 335 | ||
326 | list_add_tail(&item->list, &m->items); | 336 | list_add_tail(&item->list, &m->items); |
327 | 337 | ||
328 | return 1; | 338 | return 1; |
329 | } | 339 | } |
330 | 340 | ||
331 | /* | 341 | /* |
332 | * menu_create() - Creates a menu handle with default settings | 342 | * menu_create() - Creates a menu handle with default settings |
333 | * | 343 | * |
334 | * title - If not NULL, points to a string that will be displayed before the | 344 | * title - If not NULL, points to a string that will be displayed before the |
335 | * list of menu items. It will be copied to internal storage, and is safe to | 345 | * list of menu items. It will be copied to internal storage, and is safe to |
336 | * discard after passing to menu_create(). | 346 | * discard after passing to menu_create(). |
337 | * | 347 | * |
338 | * timeout - A delay in seconds to wait for user input. If 0, timeout is | 348 | * timeout - A delay in seconds to wait for user input. If 0, timeout is |
339 | * disabled, and the default choice will be returned unless prompt is 1. | 349 | * disabled, and the default choice will be returned unless prompt is 1. |
340 | * | 350 | * |
341 | * prompt - If 0, don't ask for user input unless there is an interrupted | 351 | * prompt - If 0, don't ask for user input unless there is an interrupted |
342 | * timeout. If 1, the user will be prompted for input regardless of the value | 352 | * timeout. If 1, the user will be prompted for input regardless of the value |
343 | * of timeout. | 353 | * of timeout. |
344 | * | 354 | * |
345 | * item_data_print - If not NULL, will be called for each item when the menu | 355 | * item_data_print - If not NULL, will be called for each item when the menu |
346 | * is displayed, with the pointer to the item's data passed as the argument. | 356 | * is displayed, with the pointer to the item's data passed as the argument. |
347 | * If NULL, each item's key will be printed instead. Since an item's key is | 357 | * If NULL, each item's key will be printed instead. Since an item's key is |
348 | * what must be entered to select an item, the item_data_print function should | 358 | * what must be entered to select an item, the item_data_print function should |
349 | * make it obvious what the key for each entry is. | 359 | * make it obvious what the key for each entry is. |
350 | * | 360 | * |
361 | * item_choice - If not NULL, will be called when asking the user to choose an | ||
362 | * item. Returns a key string corresponding to the choosen item or NULL if | ||
363 | * no item has been selected. | ||
364 | * | ||
365 | * item_choice_data - Will be passed as the argument to the item_choice function | ||
366 | * | ||
351 | * Returns a pointer to the menu if successful, or NULL if there is | 367 | * Returns a pointer to the menu if successful, or NULL if there is |
352 | * insufficient memory available to create the menu. | 368 | * insufficient memory available to create the menu. |
353 | */ | 369 | */ |
354 | struct menu *menu_create(char *title, int timeout, int prompt, | 370 | struct menu *menu_create(char *title, int timeout, int prompt, |
355 | void (*item_data_print)(void *)) | 371 | void (*item_data_print)(void *), |
372 | char *(*item_choice)(void *), | ||
373 | void *item_choice_data) | ||
356 | { | 374 | { |
357 | struct menu *m; | 375 | struct menu *m; |
358 | 376 | ||
359 | m = malloc(sizeof *m); | 377 | m = malloc(sizeof *m); |
360 | 378 | ||
361 | if (!m) | 379 | if (!m) |
362 | return NULL; | 380 | return NULL; |
363 | 381 | ||
364 | m->default_item = NULL; | 382 | m->default_item = NULL; |
365 | m->prompt = prompt; | 383 | m->prompt = prompt; |
366 | m->timeout = timeout; | 384 | m->timeout = timeout; |
367 | m->item_data_print = item_data_print; | 385 | m->item_data_print = item_data_print; |
386 | m->item_choice = item_choice; | ||
387 | m->item_choice_data = item_choice_data; | ||
368 | 388 | ||
369 | if (title) { | 389 | if (title) { |
370 | m->title = strdup(title); | 390 | m->title = strdup(title); |
371 | if (!m->title) { | 391 | if (!m->title) { |
372 | free(m); | 392 | free(m); |
373 | return NULL; | 393 | return NULL; |
374 | } | 394 | } |
375 | } else | 395 | } else |
376 | m->title = NULL; | 396 | m->title = NULL; |
377 | 397 | ||
378 | 398 | ||
379 | INIT_LIST_HEAD(&m->items); | 399 | INIT_LIST_HEAD(&m->items); |
380 | 400 | ||
381 | return m; | 401 | return m; |
382 | } | 402 | } |
383 | 403 | ||
384 | /* | 404 | /* |
385 | * menu_destroy() - frees the memory used by a menu and its items. | 405 | * menu_destroy() - frees the memory used by a menu and its items. |
386 | * | 406 | * |
387 | * m - Points to a menu created by menu_create(). | 407 | * m - Points to a menu created by menu_create(). |
388 | * | 408 | * |
389 | * Returns 1 if successful, or -EINVAL if m is NULL. | 409 | * Returns 1 if successful, or -EINVAL if m is NULL. |
390 | */ | 410 | */ |
391 | int menu_destroy(struct menu *m) | 411 | int menu_destroy(struct menu *m) |
392 | { | 412 | { |
393 | if (!m) | 413 | if (!m) |
394 | return -EINVAL; | 414 | return -EINVAL; |
395 | 415 | ||
396 | menu_items_iter(m, menu_item_destroy, NULL); | 416 | menu_items_iter(m, menu_item_destroy, NULL); |
397 | 417 | ||
398 | if (m->title) | 418 | if (m->title) |
399 | free(m->title); | 419 | free(m->title); |
400 | 420 | ||
401 | free(m); | 421 | free(m); |
402 | 422 | ||
403 | return 1; | 423 | return 1; |
404 | } | 424 | } |
405 | 425 |
doc/README.bootmenu
File was created | 1 | /* | |
2 | * (C) Copyright 2011-2012 Pali Rohรกr <pali.rohar@gmail.com> | ||
3 | * | ||
4 | * See file CREDITS for list of people who contributed to this | ||
5 | * project. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
20 | * MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | ANSI terminal bootmenu command | ||
24 | |||
25 | The "bootmenu" command uses U-Boot menu interfaces and provides | ||
26 | a simple mechanism for creating menus with different boot items. | ||
27 | The cursor keys "Up" and "Down" are used for navigation through | ||
28 | the items. Current active menu item is highlighted and can be | ||
29 | selected using the "Enter" key. The selection of the highlighted | ||
30 | menu entry invokes an U-Boot command (or a list of commands) | ||
31 | associated with this menu entry. | ||
32 | |||
33 | The "bootmenu" command interprets ANSI escape sequencies, so | ||
34 | an ANSI terminal is required for proper menu rendering and item | ||
35 | selection. | ||
36 | |||
37 | The assembling of the menu is done via a set of environment variables | ||
38 | "bootmenu_<num>" and "bootmenu_delay", i.e.: | ||
39 | |||
40 | bootmenu_delay=<delay> | ||
41 | bootmenu_<num>="<title>=<commands>" | ||
42 | |||
43 | <delay> is the autoboot delay in seconds, after which the first | ||
44 | menu entry will be selected automatically | ||
45 | |||
46 | <num> is the boot menu entry number, starting from zero | ||
47 | |||
48 | <title> is the text of the menu entry shown on the console | ||
49 | or on the boot screen | ||
50 | |||
51 | <commands> are commands which will be executed when a menu | ||
52 | entry is selected | ||
53 | |||
54 | (title and commands are separated by first appearance of '=' | ||
55 | character in the environment variable) | ||
56 | |||
57 | First (optional) argument of the "bootmenu" command is a delay specifier | ||
58 | and it overrides the delay value defined by "bootmenu_delay" environment | ||
59 | variable. If the environment variable "bootmenu_delay" is not set or if | ||
60 | the argument of the "bootmenu" command is not specified, the default delay | ||
61 | will be CONFIG_BOOTDELAY. If delay is 0, no menu entries will be shown on | ||
62 | the console (or on the screen) and the command of the first menu entry will | ||
63 | be called immediately. If delay is less then 0, bootmenu will be shown and | ||
64 | autoboot will be disabled. | ||
65 | |||
66 | Bootmenu always adds menu entry "U-Boot console" at the end of all menu | ||
67 | entries specified by environment variables. When selecting this entry | ||
68 | the bootmenu terminates and the usual U-Boot command prompt is presented | ||
69 | to the user. | ||
70 | |||
71 | Example environment: | ||
72 | |||
73 | setenv bootmenu_0 Boot 1. kernel=bootm 0x82000000 # Set first menu entry | ||
74 | setenv bootmenu_1 Boot 2. kernel=bootm 0x83000000 # Set second menu entry | ||
75 | setenv bootmenu_2 Reset board=reset # Set third menu entry | ||
76 | setenv bootmenu_3 U-Boot boot order=boot # Set fourth menu entry | ||
77 | bootmenu 20 # Run bootmenu with autoboot delay 20s | ||
78 | |||
79 | |||
80 | The above example will be rendered as below | ||
81 | (without decorating rectangle): | ||
82 | |||
83 | โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | ||
84 | โ โ | ||
85 | โ *** U-Boot Boot Menu *** โ | ||
86 | โ โ | ||
87 | โ Boot 1. kernel โ | ||
88 | โ Boot 2. kernel โ | ||
89 | โ Reset board โ | ||
90 | โ U-Boot boot order โ | ||
91 | โ U-Boot console โ | ||
92 | โ โ | ||
93 | โ Hit any key to stop autoboot: 20 โ | ||
94 | โ Press UP/DOWN to move, ENTER to select โ | ||
95 | โ โ | ||
96 | โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | ||
97 | |||
98 | Selected menu entry will be highlighted - it will have inverted | ||
99 | background and text colors. | ||
100 | |||
101 | To enable the "bootmenu" command add following definitions to the | ||
102 | board config file: | ||
103 | |||
104 | #define CONFIG_CMD_BOOTMENU | ||
105 | #define CONFIG_MENU | ||
106 | |||
107 | To run the bootmenu at startup add these additional definitions: | ||
108 | |||
109 | #define CONFIG_AUTOBOOT_KEYED | ||
110 | #define CONFIG_BOOTDELAY 30 | ||
111 | #define CONFIG_MENU_SHOW | ||
112 | |||
113 | When you intend to use the bootmenu on color frame buffer console, | ||
114 | make sure to additionally define CONFIG_CFB_CONSOLE_ANSI in the | ||
115 | board config file. | ||
116 |
doc/README.menu
1 | /* | 1 | /* |
2 | * Copyright 2010-2011 Calxeda, Inc. | 2 | * Copyright 2010-2011 Calxeda, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 5 | * under the terms of the GNU General Public License as published by the Free |
6 | * Software Foundation; either version 2 of the License, or (at your option) | 6 | * Software Foundation; either version 2 of the License, or (at your option) |
7 | * any later version. | 7 | * any later version. |
8 | * | 8 | * |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along with | 14 | * You should have received a copy of the GNU General Public License along with |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | U-boot provides a set of interfaces for creating and using simple, text | 18 | U-boot provides a set of interfaces for creating and using simple, text |
19 | based menus. Menus are displayed as lists of labeled entries on the | 19 | based menus. Menus are displayed as lists of labeled entries on the |
20 | console, and an entry can be selected by entering its label. | 20 | console, and an entry can be selected by entering its label. |
21 | 21 | ||
22 | To use the menu code, enable CONFIG_MENU, and include "menu.h" where | 22 | To use the menu code, enable CONFIG_MENU, and include "menu.h" where |
23 | the interfaces should be available. | 23 | the interfaces should be available. |
24 | 24 | ||
25 | Menus are composed of items. Each item has a key used to identify it in | 25 | Menus are composed of items. Each item has a key used to identify it in |
26 | the menu, and an opaque pointer to data controlled by the consumer. | 26 | the menu, and an opaque pointer to data controlled by the consumer. |
27 | 27 | ||
28 | If you want to show a menu, instead starting the shell, define | 28 | If you want to show a menu, instead starting the shell, define |
29 | CONFIG_MENU_SHOW. You have to code the int menu_show(int bootdelay) | 29 | CONFIG_MENU_SHOW. You have to code the int menu_show(int bootdelay) |
30 | function, which handle your menu. This function returns the remaining | 30 | function, which handle your menu. This function returns the remaining |
31 | bootdelay. | 31 | bootdelay. |
32 | 32 | ||
33 | Interfaces | 33 | Interfaces |
34 | ---------- | 34 | ---------- |
35 | #include "menu.h" | 35 | #include "menu.h" |
36 | 36 | ||
37 | /* | 37 | /* |
38 | * Consumers of the menu interfaces will use a struct menu * as the | 38 | * Consumers of the menu interfaces will use a struct menu * as the |
39 | * handle for a menu. struct menu is only fully defined in menu.c, | 39 | * handle for a menu. struct menu is only fully defined in menu.c, |
40 | * preventing consumers of the menu interfaces from accessing its | 40 | * preventing consumers of the menu interfaces from accessing its |
41 | * contents directly. | 41 | * contents directly. |
42 | */ | 42 | */ |
43 | struct menu; | 43 | struct menu; |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * NOTE: See comments in common/menu.c for more detailed documentation on | 46 | * NOTE: See comments in common/menu.c for more detailed documentation on |
47 | * these interfaces. | 47 | * these interfaces. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * menu_create() - Creates a menu handle with default settings | 51 | * menu_create() - Creates a menu handle with default settings |
52 | */ | 52 | */ |
53 | struct menu *menu_create(char *title, int timeout, int prompt, | 53 | struct menu *menu_create(char *title, int timeout, int prompt, |
54 | void (*item_data_print)(void *)); | 54 | void (*item_data_print)(void *), |
55 | char *(*item_choice)(void *), | ||
56 | void *item_choice_data); | ||
55 | 57 | ||
56 | /* | 58 | /* |
57 | * menu_item_add() - Adds or replaces a menu item | 59 | * menu_item_add() - Adds or replaces a menu item |
58 | */ | 60 | */ |
59 | int menu_item_add(struct menu *m, char *item_key, void *item_data); | 61 | int menu_item_add(struct menu *m, char *item_key, void *item_data); |
60 | 62 | ||
61 | /* | 63 | /* |
62 | * menu_default_set() - Sets the default choice for the menu | 64 | * menu_default_set() - Sets the default choice for the menu |
63 | */ | 65 | */ |
64 | int menu_default_set(struct menu *m, char *item_key); | 66 | int menu_default_set(struct menu *m, char *item_key); |
67 | |||
68 | /* | ||
69 | * menu_default_choice() - Set *choice to point to the default item's data | ||
70 | */ | ||
71 | int menu_default_choice(struct menu *m, void **choice); | ||
65 | 72 | ||
66 | /* | 73 | /* |
67 | * menu_get_choice() - Returns the user's selected menu entry, or the | 74 | * menu_get_choice() - Returns the user's selected menu entry, or the |
68 | * default if the menu is set to not prompt or the timeout expires. | 75 | * default if the menu is set to not prompt or the timeout expires. |
69 | */ | 76 | */ |
70 | int menu_get_choice(struct menu *m, void **choice); | 77 | int menu_get_choice(struct menu *m, void **choice); |
71 | 78 | ||
72 | /* | 79 | /* |
73 | * menu_destroy() - frees the memory used by a menu and its items. | 80 | * menu_destroy() - frees the memory used by a menu and its items. |
74 | */ | 81 | */ |
75 | int menu_destroy(struct menu *m); | 82 | int menu_destroy(struct menu *m); |
76 | 83 | ||
77 | /* | 84 | /* |
78 | * menu_display_statusline(struct menu *m); | 85 | * menu_display_statusline(struct menu *m); |
79 | * shows a statusline for every menu_display call. | 86 | * shows a statusline for every menu_display call. |
80 | */ | 87 | */ |
81 | void menu_display_statusline(struct menu *m); | 88 | void menu_display_statusline(struct menu *m); |
82 | 89 | ||
83 | Example Code | 90 | Example Code |
84 | ------------ | 91 | ------------ |
85 | This example creates a menu that always prompts, and allows the user | 92 | This example creates a menu that always prompts, and allows the user |
86 | to pick from a list of tools. The item key and data are the same. | 93 | to pick from a list of tools. The item key and data are the same. |
87 | 94 | ||
88 | #include "menu.h" | 95 | #include "menu.h" |
89 | 96 | ||
90 | char *tools[] = { | 97 | char *tools[] = { |
91 | "Hammer", | 98 | "Hammer", |
92 | "Screwdriver", | 99 | "Screwdriver", |
93 | "Nail gun", | 100 | "Nail gun", |
94 | NULL | 101 | NULL |
95 | }; | 102 | }; |
96 | 103 | ||
97 | char *pick_a_tool(void) | 104 | char *pick_a_tool(void) |
98 | { | 105 | { |
99 | struct menu *m; | 106 | struct menu *m; |
100 | int i; | 107 | int i; |
101 | char *tool = NULL; | 108 | char *tool = NULL; |
102 | 109 | ||
103 | m = menu_create("Tools", 0, 1, NULL); | 110 | m = menu_create("Tools", 0, 1, NULL); |
104 | 111 | ||
105 | for(i = 0; tools[i]; i++) { | 112 | for(i = 0; tools[i]; i++) { |
106 | if (menu_item_add(m, tools[i], tools[i]) != 1) { | 113 | if (menu_item_add(m, tools[i], tools[i]) != 1) { |
107 | printf("failed to add item!"); | 114 | printf("failed to add item!"); |
108 | menu_destroy(m); | 115 | menu_destroy(m); |
109 | return NULL; | 116 | return NULL; |
110 | } | 117 | } |
111 | } | 118 | } |
112 | 119 | ||
113 | if (menu_get_choice(m, (void **)&tool) != 1) | 120 | if (menu_get_choice(m, (void **)&tool) != 1) |
114 | printf("Problem picking tool!\n"); | 121 | printf("Problem picking tool!\n"); |
115 | 122 | ||
116 | menu_destroy(m); | 123 | menu_destroy(m); |
117 | 124 | ||
118 | return tool; | 125 | return tool; |
119 | } | 126 | } |
120 | 127 | ||
121 | void caller(void) | 128 | void caller(void) |
122 | { | 129 | { |
123 | char *tool = pick_a_tool(); | 130 | char *tool = pick_a_tool(); |
124 | 131 | ||
125 | if (tool) { | 132 | if (tool) { |
126 | printf("picked a tool: %s\n", tool); | 133 | printf("picked a tool: %s\n", tool); |
127 | use_tool(tool); | 134 | use_tool(tool); |
128 | } | 135 | } |
129 | } | 136 | } |
130 | 137 |
include/ansi.h
File was created | 1 | /* | |
2 | * (C) Copyright 2012 | ||
3 | * Pali Rohรกr <pali.rohar@gmail.com> | ||
4 | * | ||
5 | * See file CREDITS for list of people who contributed to this | ||
6 | * project. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of | ||
11 | * the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
21 | * MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * ANSI terminal | ||
26 | */ | ||
27 | |||
28 | #define ANSI_CURSOR_UP "\e[%dA" | ||
29 | #define ANSI_CURSOR_DOWN "\e[%dB" | ||
30 | #define ANSI_CURSOR_FORWARD "\e[%dC" | ||
31 | #define ANSI_CURSOR_BACK "\e[%dD" | ||
32 | #define ANSI_CURSOR_NEXTLINE "\e[%dE" | ||
33 | #define ANSI_CURSOR_PREVIOUSLINE "\e[%dF" | ||
34 | #define ANSI_CURSOR_COLUMN "\e[%dG" | ||
35 | #define ANSI_CURSOR_POSITION "\e[%d;%dH" | ||
36 | #define ANSI_CURSOR_SHOW "\e[?25h" | ||
37 | #define ANSI_CURSOR_HIDE "\e[?25l" | ||
38 | #define ANSI_CLEAR_CONSOLE "\e[2J" | ||
39 | #define ANSI_CLEAR_LINE_TO_END "\e[0K" | ||
40 | #define ANSI_CLEAR_LINE "\e[2K" | ||
41 | #define ANSI_COLOR_RESET "\e[0m" | ||
42 | #define ANSI_COLOR_REVERSE "\e[7m" | ||
43 |
include/configs/nokia_rx51.h
1 | /* | 1 | /* |
2 | * (C) Copyright 2011-2012 | 2 | * (C) Copyright 2011-2012 |
3 | * Pali Rohรกr <pali.rohar@gmail.com> | 3 | * Pali Rohรกr <pali.rohar@gmail.com> |
4 | * | 4 | * |
5 | * (C) Copyright 2010 | 5 | * (C) Copyright 2010 |
6 | * Alistair Buxton <a.j.buxton@gmail.com> | 6 | * Alistair Buxton <a.j.buxton@gmail.com> |
7 | * | 7 | * |
8 | * Derived from Beagle Board code: | 8 | * Derived from Beagle Board code: |
9 | * (C) Copyright 2006-2008 | 9 | * (C) Copyright 2006-2008 |
10 | * Texas Instruments. | 10 | * Texas Instruments. |
11 | * Richard Woodruff <r-woodruff2@ti.com> | 11 | * Richard Woodruff <r-woodruff2@ti.com> |
12 | * Syed Mohammed Khasim <x0khasim@ti.com> | 12 | * Syed Mohammed Khasim <x0khasim@ti.com> |
13 | * | 13 | * |
14 | * Configuration settings for the Nokia RX-51 aka N900. | 14 | * Configuration settings for the Nokia RX-51 aka N900. |
15 | * | 15 | * |
16 | * See file CREDITS for list of people who contributed to this | 16 | * See file CREDITS for list of people who contributed to this |
17 | * project. | 17 | * project. |
18 | * | 18 | * |
19 | * This program is free software; you can redistribute it and/or | 19 | * This program is free software; you can redistribute it and/or |
20 | * modify it under the terms of the GNU General Public License as | 20 | * modify it under the terms of the GNU General Public License as |
21 | * published by the Free Software Foundation; either version 2 of | 21 | * published by the Free Software Foundation; either version 2 of |
22 | * the License, or (at your option) any later version. | 22 | * the License, or (at your option) any later version. |
23 | * | 23 | * |
24 | * This program is distributed in the hope that it will be useful, | 24 | * This program is distributed in the hope that it will be useful, |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
27 | * GNU General Public License for more details. | 27 | * GNU General Public License for more details. |
28 | * | 28 | * |
29 | * You should have received a copy of the GNU General Public License | 29 | * You should have received a copy of the GNU General Public License |
30 | * along with this program; if not, write to the Free Software | 30 | * along with this program; if not, write to the Free Software |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
32 | * MA 02111-1307 USA | 32 | * MA 02111-1307 USA |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #ifndef __CONFIG_H | 35 | #ifndef __CONFIG_H |
36 | #define __CONFIG_H | 36 | #define __CONFIG_H |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * High Level Configuration Options | 39 | * High Level Configuration Options |
40 | */ | 40 | */ |
41 | 41 | ||
42 | #define CONFIG_OMAP /* in a TI OMAP core */ | 42 | #define CONFIG_OMAP /* in a TI OMAP core */ |
43 | #define CONFIG_OMAP34XX /* which is a 34XX */ | 43 | #define CONFIG_OMAP34XX /* which is a 34XX */ |
44 | #define CONFIG_OMAP3430 /* which is in a 3430 */ | 44 | #define CONFIG_OMAP3430 /* which is in a 3430 */ |
45 | #define CONFIG_OMAP3_RX51 /* working with RX51 */ | 45 | #define CONFIG_OMAP3_RX51 /* working with RX51 */ |
46 | #define CONFIG_SYS_L2CACHE_OFF /* pretend there is no L2 CACHE */ | 46 | #define CONFIG_SYS_L2CACHE_OFF /* pretend there is no L2 CACHE */ |
47 | 47 | ||
48 | #define CONFIG_MACH_TYPE MACH_TYPE_NOKIA_RX51 | 48 | #define CONFIG_MACH_TYPE MACH_TYPE_NOKIA_RX51 |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * Nokia X-Loader loading secondary image to address 0x80400000 | 51 | * Nokia X-Loader loading secondary image to address 0x80400000 |
52 | * NOLO loading boot image to random place, so it doesn't really | 52 | * NOLO loading boot image to random place, so it doesn't really |
53 | * matter what we set this to. We have to copy u-boot to this address | 53 | * matter what we set this to. We have to copy u-boot to this address |
54 | */ | 54 | */ |
55 | #define CONFIG_SYS_TEXT_BASE 0x80008000 | 55 | #define CONFIG_SYS_TEXT_BASE 0x80008000 |
56 | 56 | ||
57 | #define CONFIG_SDRC /* The chip has SDRC controller */ | 57 | #define CONFIG_SDRC /* The chip has SDRC controller */ |
58 | 58 | ||
59 | #include <asm/arch/cpu.h> /* get chip and board defs */ | 59 | #include <asm/arch/cpu.h> /* get chip and board defs */ |
60 | #include <asm/arch/omap3.h> | 60 | #include <asm/arch/omap3.h> |
61 | #include <asm/arch/mem.h> | 61 | #include <asm/arch/mem.h> |
62 | #include <linux/stringify.h> | 62 | #include <linux/stringify.h> |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Display CPU and Board information | 65 | * Display CPU and Board information |
66 | */ | 66 | */ |
67 | #define CONFIG_DISPLAY_CPUINFO | 67 | #define CONFIG_DISPLAY_CPUINFO |
68 | #define CONFIG_DISPLAY_BOARDINFO | 68 | #define CONFIG_DISPLAY_BOARDINFO |
69 | 69 | ||
70 | /* Clock Defines */ | 70 | /* Clock Defines */ |
71 | #define V_OSCK 26000000 /* Clock output from T2 */ | 71 | #define V_OSCK 26000000 /* Clock output from T2 */ |
72 | #define V_SCLK (V_OSCK >> 1) | 72 | #define V_SCLK (V_OSCK >> 1) |
73 | 73 | ||
74 | #undef CONFIG_USE_IRQ /* no support for IRQs */ | 74 | #undef CONFIG_USE_IRQ /* no support for IRQs */ |
75 | #define CONFIG_MISC_INIT_R | 75 | #define CONFIG_MISC_INIT_R |
76 | #define CONFIG_SKIP_LOWLEVEL_INIT /* X-Loader set everything up */ | 76 | #define CONFIG_SKIP_LOWLEVEL_INIT /* X-Loader set everything up */ |
77 | 77 | ||
78 | #define CONFIG_CMDLINE_TAG /* enable passing kernel command line string */ | 78 | #define CONFIG_CMDLINE_TAG /* enable passing kernel command line string */ |
79 | #define CONFIG_INITRD_TAG /* enable passing initrd */ | 79 | #define CONFIG_INITRD_TAG /* enable passing initrd */ |
80 | #define CONFIG_REVISION_TAG /* enable passing revision tag*/ | 80 | #define CONFIG_REVISION_TAG /* enable passing revision tag*/ |
81 | #define CONFIG_SETUP_MEMORY_TAGS /* enable memory tag */ | 81 | #define CONFIG_SETUP_MEMORY_TAGS /* enable memory tag */ |
82 | 82 | ||
83 | /* | 83 | /* |
84 | * Size of malloc() pool | 84 | * Size of malloc() pool |
85 | */ | 85 | */ |
86 | #define CONFIG_ENV_SIZE (128 << 10) | 86 | #define CONFIG_ENV_SIZE (128 << 10) |
87 | #define CONFIG_UBI_SIZE (512 << 10) | 87 | #define CONFIG_UBI_SIZE (512 << 10) |
88 | #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + CONFIG_UBI_SIZE + \ | 88 | #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + CONFIG_UBI_SIZE + \ |
89 | (128 << 10)) | 89 | (128 << 10)) |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * Hardware drivers | 92 | * Hardware drivers |
93 | */ | 93 | */ |
94 | 94 | ||
95 | /* | 95 | /* |
96 | * NS16550 Configuration | 96 | * NS16550 Configuration |
97 | */ | 97 | */ |
98 | #define V_NS16550_CLK 48000000 /* 48MHz (APLL96/2) */ | 98 | #define V_NS16550_CLK 48000000 /* 48MHz (APLL96/2) */ |
99 | 99 | ||
100 | #define CONFIG_SYS_NS16550 | 100 | #define CONFIG_SYS_NS16550 |
101 | #define CONFIG_SYS_NS16550_SERIAL | 101 | #define CONFIG_SYS_NS16550_SERIAL |
102 | #define CONFIG_SYS_NS16550_REG_SIZE (-4) | 102 | #define CONFIG_SYS_NS16550_REG_SIZE (-4) |
103 | #define CONFIG_SYS_NS16550_CLK V_NS16550_CLK | 103 | #define CONFIG_SYS_NS16550_CLK V_NS16550_CLK |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * select serial console configuration | 106 | * select serial console configuration |
107 | */ | 107 | */ |
108 | #define CONFIG_CONS_INDEX 3 | 108 | #define CONFIG_CONS_INDEX 3 |
109 | #define CONFIG_SYS_NS16550_COM3 OMAP34XX_UART3 | 109 | #define CONFIG_SYS_NS16550_COM3 OMAP34XX_UART3 |
110 | #define CONFIG_SERIAL3 3 /* UART3 on RX-51 */ | 110 | #define CONFIG_SERIAL3 3 /* UART3 on RX-51 */ |
111 | 111 | ||
112 | /* allow to overwrite serial and ethaddr */ | 112 | /* allow to overwrite serial and ethaddr */ |
113 | #define CONFIG_ENV_OVERWRITE | 113 | #define CONFIG_ENV_OVERWRITE |
114 | #define CONFIG_BAUDRATE 115200 | 114 | #define CONFIG_BAUDRATE 115200 |
115 | #define CONFIG_SYS_BAUDRATE_TABLE { 4800, 9600, 19200, 38400, 57600, 115200 } | 115 | #define CONFIG_SYS_BAUDRATE_TABLE { 4800, 9600, 19200, 38400, 57600, 115200 } |
116 | #define CONFIG_MMC | 116 | #define CONFIG_MMC |
117 | #define CONFIG_GENERIC_MMC | 117 | #define CONFIG_GENERIC_MMC |
118 | #define CONFIG_OMAP_HSMMC | 118 | #define CONFIG_OMAP_HSMMC |
119 | #define CONFIG_DOS_PARTITION | 119 | #define CONFIG_DOS_PARTITION |
120 | 120 | ||
121 | /* USB */ | 121 | /* USB */ |
122 | #define CONFIG_MUSB_UDC | 122 | #define CONFIG_MUSB_UDC |
123 | #define CONFIG_MUSB_HDC | 123 | #define CONFIG_MUSB_HDC |
124 | #define CONFIG_USB_OMAP3 | 124 | #define CONFIG_USB_OMAP3 |
125 | #define CONFIG_TWL4030_USB | 125 | #define CONFIG_TWL4030_USB |
126 | 126 | ||
127 | /* USB device configuration */ | 127 | /* USB device configuration */ |
128 | #define CONFIG_USB_DEVICE | 128 | #define CONFIG_USB_DEVICE |
129 | #define CONFIG_USBD_VENDORID 0x0421 | 129 | #define CONFIG_USBD_VENDORID 0x0421 |
130 | #define CONFIG_USBD_PRODUCTID 0x01c8 | 130 | #define CONFIG_USBD_PRODUCTID 0x01c8 |
131 | #define CONFIG_USBD_MANUFACTURER "Nokia" | 131 | #define CONFIG_USBD_MANUFACTURER "Nokia" |
132 | #define CONFIG_USBD_PRODUCT_NAME "N900" | 132 | #define CONFIG_USBD_PRODUCT_NAME "N900" |
133 | 133 | ||
134 | #define CONFIG_SYS_CONSOLE_IS_IN_ENV | 134 | #define CONFIG_SYS_CONSOLE_IS_IN_ENV |
135 | #define CONFIG_SYS_NO_FLASH | 135 | #define CONFIG_SYS_NO_FLASH |
136 | 136 | ||
137 | /* commands to include */ | 137 | /* commands to include */ |
138 | #include <config_cmd_default.h> | 138 | #include <config_cmd_default.h> |
139 | 139 | ||
140 | #define CONFIG_CMD_EXT2 /* EXT2 Support */ | 140 | #define CONFIG_CMD_EXT2 /* EXT2 Support */ |
141 | #define CONFIG_CMD_EXT4 /* EXT4 Support */ | 141 | #define CONFIG_CMD_EXT4 /* EXT4 Support */ |
142 | #define CONFIG_CMD_FAT /* FAT support */ | 142 | #define CONFIG_CMD_FAT /* FAT support */ |
143 | 143 | ||
144 | #define CONFIG_CMD_I2C /* I2C serial bus support */ | 144 | #define CONFIG_CMD_I2C /* I2C serial bus support */ |
145 | #define CONFIG_CMD_MMC /* MMC support */ | 145 | #define CONFIG_CMD_MMC /* MMC support */ |
146 | #define CONFIG_CMD_GPIO /* Enable gpio command */ | 146 | #define CONFIG_CMD_GPIO /* Enable gpio command */ |
147 | 147 | ||
148 | #define CONFIG_CMDLINE_EDITING /* add command line history */ | 148 | #define CONFIG_CMDLINE_EDITING /* add command line history */ |
149 | #define CONFIG_AUTO_COMPLETE /* add autocompletion support */ | 149 | #define CONFIG_AUTO_COMPLETE /* add autocompletion support */ |
150 | 150 | ||
151 | #define CONFIG_CMD_BOOTMENU /* ANSI terminal Boot Menu */ | ||
151 | #define CONFIG_CMD_CLEAR /* ANSI terminal clear screen command */ | 152 | #define CONFIG_CMD_CLEAR /* ANSI terminal clear screen command */ |
152 | 153 | ||
153 | #ifdef ONENAND_SUPPORT | 154 | #ifdef ONENAND_SUPPORT |
154 | 155 | ||
155 | #define CONFIG_CMD_ONENAND /* ONENAND support */ | 156 | #define CONFIG_CMD_ONENAND /* ONENAND support */ |
156 | #define CONFIG_CMD_MTDPARTS /* mtd parts support */ | 157 | #define CONFIG_CMD_MTDPARTS /* mtd parts support */ |
157 | 158 | ||
158 | #ifdef UBIFS_SUPPORT | 159 | #ifdef UBIFS_SUPPORT |
159 | #define CONFIG_CMD_UBI /* UBI Support */ | 160 | #define CONFIG_CMD_UBI /* UBI Support */ |
160 | #define CONFIG_CMD_UBIFS /* UBIFS Support */ | 161 | #define CONFIG_CMD_UBIFS /* UBIFS Support */ |
161 | #endif | 162 | #endif |
162 | 163 | ||
163 | #endif | 164 | #endif |
164 | 165 | ||
165 | /* commands not needed from config_cmd_default.h */ | 166 | /* commands not needed from config_cmd_default.h */ |
166 | #undef CONFIG_CMD_FPGA /* FPGA configuration Support */ | 167 | #undef CONFIG_CMD_FPGA /* FPGA configuration Support */ |
167 | #undef CONFIG_CMD_IMI /* iminfo */ | 168 | #undef CONFIG_CMD_IMI /* iminfo */ |
168 | #undef CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */ | 169 | #undef CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */ |
169 | #undef CONFIG_CMD_NFS /* NFS support */ | 170 | #undef CONFIG_CMD_NFS /* NFS support */ |
170 | #undef CONFIG_CMD_SAVEENV /* saveenv */ | 171 | #undef CONFIG_CMD_SAVEENV /* saveenv */ |
171 | #undef CONFIG_CMD_SETGETDCR /* DCR support on 4xx */ | 172 | #undef CONFIG_CMD_SETGETDCR /* DCR support on 4xx */ |
172 | 173 | ||
173 | #define CONFIG_OMAP3_SPI | 174 | #define CONFIG_OMAP3_SPI |
174 | #define CONFIG_HARD_I2C | 175 | #define CONFIG_HARD_I2C |
175 | #define CONFIG_SYS_I2C_SPEED 100000 | 176 | #define CONFIG_SYS_I2C_SPEED 100000 |
176 | #define CONFIG_SYS_I2C_SLAVE 1 | 177 | #define CONFIG_SYS_I2C_SLAVE 1 |
177 | #define CONFIG_DRIVER_OMAP34XX_I2C | 178 | #define CONFIG_DRIVER_OMAP34XX_I2C |
178 | 179 | ||
179 | /* | 180 | /* |
180 | * TWL4030 | 181 | * TWL4030 |
181 | */ | 182 | */ |
182 | #define CONFIG_TWL4030_POWER | 183 | #define CONFIG_TWL4030_POWER |
183 | #define CONFIG_TWL4030_LED | 184 | #define CONFIG_TWL4030_LED |
184 | #define CONFIG_TWL4030_KEYPAD | 185 | #define CONFIG_TWL4030_KEYPAD |
185 | 186 | ||
186 | #define CONFIG_OMAP_GPIO | 187 | #define CONFIG_OMAP_GPIO |
187 | #define GPIO_SLIDE 71 | 188 | #define GPIO_SLIDE 71 |
188 | 189 | ||
189 | /* | 190 | /* |
190 | * Board ONENAND Info. | 191 | * Board ONENAND Info. |
191 | */ | 192 | */ |
192 | 193 | ||
193 | #define PART1_NAME "bootloader" | 194 | #define PART1_NAME "bootloader" |
194 | #define PART1_SIZE 128 | 195 | #define PART1_SIZE 128 |
195 | #define PART1_MULL 1024 | 196 | #define PART1_MULL 1024 |
196 | #define PART1_SUFF "k" | 197 | #define PART1_SUFF "k" |
197 | #define PART1_OFFS 0x00000000 | 198 | #define PART1_OFFS 0x00000000 |
198 | #define PART1_MASK 0x00000003 | 199 | #define PART1_MASK 0x00000003 |
199 | 200 | ||
200 | #define PART2_NAME "config" | 201 | #define PART2_NAME "config" |
201 | #define PART2_SIZE 384 | 202 | #define PART2_SIZE 384 |
202 | #define PART2_MULL 1024 | 203 | #define PART2_MULL 1024 |
203 | #define PART2_SUFF "k" | 204 | #define PART2_SUFF "k" |
204 | #define PART2_OFFS 0x00020000 | 205 | #define PART2_OFFS 0x00020000 |
205 | #define PART2_MASK 0x00000000 | 206 | #define PART2_MASK 0x00000000 |
206 | 207 | ||
207 | #define PART3_NAME "log" | 208 | #define PART3_NAME "log" |
208 | #define PART3_SIZE 256 | 209 | #define PART3_SIZE 256 |
209 | #define PART3_MULL 1024 | 210 | #define PART3_MULL 1024 |
210 | #define PART3_SUFF "k" | 211 | #define PART3_SUFF "k" |
211 | #define PART3_OFFS 0x00080000 | 212 | #define PART3_OFFS 0x00080000 |
212 | #define PART3_MASK 0x00000000 | 213 | #define PART3_MASK 0x00000000 |
213 | 214 | ||
214 | #define PART4_NAME "kernel" | 215 | #define PART4_NAME "kernel" |
215 | #define PART4_SIZE 2 | 216 | #define PART4_SIZE 2 |
216 | #define PART4_MULL 1024*1024 | 217 | #define PART4_MULL 1024*1024 |
217 | #define PART4_SUFF "m" | 218 | #define PART4_SUFF "m" |
218 | #define PART4_OFFS 0x000c0000 | 219 | #define PART4_OFFS 0x000c0000 |
219 | #define PART4_MASK 0x00000000 | 220 | #define PART4_MASK 0x00000000 |
220 | 221 | ||
221 | #define PART5_NAME "initfs" | 222 | #define PART5_NAME "initfs" |
222 | #define PART5_SIZE 2 | 223 | #define PART5_SIZE 2 |
223 | #define PART5_MULL 1024*1024 | 224 | #define PART5_MULL 1024*1024 |
224 | #define PART5_SUFF "m" | 225 | #define PART5_SUFF "m" |
225 | #define PART5_OFFS 0x002c0000 | 226 | #define PART5_OFFS 0x002c0000 |
226 | #define PART5_MASK 0x00000000 | 227 | #define PART5_MASK 0x00000000 |
227 | 228 | ||
228 | #define PART6_NAME "rootfs" | 229 | #define PART6_NAME "rootfs" |
229 | #define PART6_SIZE 257280 | 230 | #define PART6_SIZE 257280 |
230 | #define PART6_MULL 1024 | 231 | #define PART6_MULL 1024 |
231 | #define PART6_SUFF "k" | 232 | #define PART6_SUFF "k" |
232 | #define PART6_OFFS 0x004c0000 | 233 | #define PART6_OFFS 0x004c0000 |
233 | #define PART6_MASK 0x00000000 | 234 | #define PART6_MASK 0x00000000 |
234 | 235 | ||
235 | #ifdef ONENAND_SUPPORT | 236 | #ifdef ONENAND_SUPPORT |
236 | 237 | ||
237 | #define PISMO1_NAND_SIZE GPMC_SIZE_128M | 238 | #define PISMO1_NAND_SIZE GPMC_SIZE_128M |
238 | #define PISMO1_ONEN_SIZE GPMC_SIZE_128M | 239 | #define PISMO1_ONEN_SIZE GPMC_SIZE_128M |
239 | #define CONFIG_SYS_ONENAND_BASE ONENAND_MAP | 240 | #define CONFIG_SYS_ONENAND_BASE ONENAND_MAP |
240 | #define CONFIG_MTD_DEVICE | 241 | #define CONFIG_MTD_DEVICE |
241 | #define CONFIG_MTD_PARTITIONS | 242 | #define CONFIG_MTD_PARTITIONS |
242 | 243 | ||
243 | #ifdef UBIFS_SUPPORT | 244 | #ifdef UBIFS_SUPPORT |
244 | #define CONFIG_RBTREE | 245 | #define CONFIG_RBTREE |
245 | #define CONFIG_LZO | 246 | #define CONFIG_LZO |
246 | #endif | 247 | #endif |
247 | 248 | ||
248 | #define MTDIDS_DEFAULT "onenand0=onenand" | 249 | #define MTDIDS_DEFAULT "onenand0=onenand" |
249 | #define MTDPARTS_DEFAULT "mtdparts=onenand:" \ | 250 | #define MTDPARTS_DEFAULT "mtdparts=onenand:" \ |
250 | __stringify(PART1_SIZE) PART1_SUFF "(" PART1_NAME ")ro," \ | 251 | __stringify(PART1_SIZE) PART1_SUFF "(" PART1_NAME ")ro," \ |
251 | __stringify(PART2_SIZE) PART2_SUFF "(" PART2_NAME ")," \ | 252 | __stringify(PART2_SIZE) PART2_SUFF "(" PART2_NAME ")," \ |
252 | __stringify(PART3_SIZE) PART3_SUFF "(" PART3_NAME ")," \ | 253 | __stringify(PART3_SIZE) PART3_SUFF "(" PART3_NAME ")," \ |
253 | __stringify(PART4_SIZE) PART4_SUFF "(" PART4_NAME ")," \ | 254 | __stringify(PART4_SIZE) PART4_SUFF "(" PART4_NAME ")," \ |
254 | __stringify(PART5_SIZE) PART5_SUFF "(" PART5_NAME ")," \ | 255 | __stringify(PART5_SIZE) PART5_SUFF "(" PART5_NAME ")," \ |
255 | "-(" PART6_NAME ")" | 256 | "-(" PART6_NAME ")" |
256 | 257 | ||
257 | #endif | 258 | #endif |
258 | 259 | ||
259 | /* Watchdog support */ | 260 | /* Watchdog support */ |
260 | #define CONFIG_HW_WATCHDOG | 261 | #define CONFIG_HW_WATCHDOG |
261 | 262 | ||
262 | /* | 263 | /* |
263 | * Framebuffer | 264 | * Framebuffer |
264 | */ | 265 | */ |
265 | /* Video console */ | 266 | /* Video console */ |
266 | #define CONFIG_VIDEO | 267 | #define CONFIG_VIDEO |
267 | #define CONFIG_CFB_CONSOLE | 268 | #define CONFIG_CFB_CONSOLE |
268 | #define CONFIG_CFB_CONSOLE_ANSI /* Enable ANSI escape codes in framebuffer */ | 269 | #define CONFIG_CFB_CONSOLE_ANSI /* Enable ANSI escape codes in framebuffer */ |
269 | #define CONFIG_VIDEO_LOGO | 270 | #define CONFIG_VIDEO_LOGO |
270 | #define VIDEO_FB_16BPP_PIXEL_SWAP | 271 | #define VIDEO_FB_16BPP_PIXEL_SWAP |
271 | #define VIDEO_FB_16BPP_WORD_SWAP | 272 | #define VIDEO_FB_16BPP_WORD_SWAP |
272 | #define CONFIG_VIDEO_SW_CURSOR | 273 | #define CONFIG_VIDEO_SW_CURSOR |
273 | #define CONFIG_SPLASH_SCREEN | 274 | #define CONFIG_SPLASH_SCREEN |
274 | 275 | ||
275 | /* functions for cfb_console */ | 276 | /* functions for cfb_console */ |
276 | #define VIDEO_KBD_INIT_FCT rx51_kp_init() | 277 | #define VIDEO_KBD_INIT_FCT rx51_kp_init() |
277 | #define VIDEO_TSTC_FCT rx51_kp_tstc | 278 | #define VIDEO_TSTC_FCT rx51_kp_tstc |
278 | #define VIDEO_GETC_FCT rx51_kp_getc | 279 | #define VIDEO_GETC_FCT rx51_kp_getc |
279 | #ifndef __ASSEMBLY__ | 280 | #ifndef __ASSEMBLY__ |
280 | int rx51_kp_init(void); | 281 | int rx51_kp_init(void); |
281 | int rx51_kp_tstc(void); | 282 | int rx51_kp_tstc(void); |
282 | int rx51_kp_getc(void); | 283 | int rx51_kp_getc(void); |
283 | #endif | 284 | #endif |
284 | 285 | ||
285 | #ifndef MTDPARTS_DEFAULT | 286 | #ifndef MTDPARTS_DEFAULT |
286 | #define MTDPARTS_DEFAULT | 287 | #define MTDPARTS_DEFAULT |
287 | #endif | 288 | #endif |
288 | 289 | ||
289 | /* Environment information */ | 290 | /* Environment information */ |
290 | #define CONFIG_BOOTDELAY 3 | ||
291 | |||
292 | #define CONFIG_EXTRA_ENV_SETTINGS \ | 291 | #define CONFIG_EXTRA_ENV_SETTINGS \ |
293 | "mtdparts=" MTDPARTS_DEFAULT "\0" \ | 292 | "mtdparts=" MTDPARTS_DEFAULT "\0" \ |
294 | "usbtty=cdc_acm\0" \ | 293 | "usbtty=cdc_acm\0" \ |
295 | "stdin=vga\0" \ | 294 | "stdin=vga\0" \ |
296 | "stdout=vga\0" \ | 295 | "stdout=vga\0" \ |
297 | "stderr=vga\0" \ | 296 | "stderr=vga\0" \ |
298 | "setcon=setenv stdin ${con};" \ | 297 | "setcon=setenv stdin ${con};" \ |
299 | "setenv stdout ${con};" \ | 298 | "setenv stdout ${con};" \ |
300 | "setenv stderr ${con}\0" \ | 299 | "setenv stderr ${con}\0" \ |
301 | "sercon=setenv con serial; run setcon\0" \ | 300 | "sercon=setenv con serial; run setcon\0" \ |
302 | "usbcon=setenv con usbtty; run setcon\0" \ | 301 | "usbcon=setenv con usbtty; run setcon\0" \ |
303 | "vgacon=setenv con vga; run setcon\0" \ | 302 | "vgacon=setenv con vga; run setcon\0" \ |
304 | "slide=gpio input " __stringify(GPIO_SLIDE) "\0" \ | 303 | "slide=gpio input " __stringify(GPIO_SLIDE) "\0" \ |
305 | "switchmmc=mmc dev ${mmcnum}\0" \ | 304 | "switchmmc=mmc dev ${mmcnum}\0" \ |
306 | "kernaddr=0x82008000\0" \ | 305 | "kernaddr=0x82008000\0" \ |
307 | "initrdaddr=0x84008000\0" \ | 306 | "initrdaddr=0x84008000\0" \ |
308 | "scriptaddr=0x86008000\0" \ | 307 | "scriptaddr=0x86008000\0" \ |
309 | "fileload=${mmctype}load mmc ${mmcnum}:${mmcpart} " \ | 308 | "fileload=${mmctype}load mmc ${mmcnum}:${mmcpart} " \ |
310 | "${loadaddr} ${mmcfile}\0" \ | 309 | "${loadaddr} ${mmcfile}\0" \ |
311 | "kernload=setenv loadaddr ${kernaddr};" \ | 310 | "kernload=setenv loadaddr ${kernaddr};" \ |
312 | "setenv mmcfile ${mmckernfile};" \ | 311 | "setenv mmcfile ${mmckernfile};" \ |
313 | "run fileload\0" \ | 312 | "run fileload\0" \ |
314 | "initrdload=setenv loadaddr ${initrdaddr};" \ | 313 | "initrdload=setenv loadaddr ${initrdaddr};" \ |
315 | "setenv mmcfile ${mmcinitrdfile};" \ | 314 | "setenv mmcfile ${mmcinitrdfile};" \ |
316 | "run fileload\0" \ | 315 | "run fileload\0" \ |
317 | "scriptload=setenv loadaddr ${scriptaddr};" \ | 316 | "scriptload=setenv loadaddr ${scriptaddr};" \ |
318 | "setenv mmcfile ${mmcscriptfile};" \ | 317 | "setenv mmcfile ${mmcscriptfile};" \ |
319 | "run fileload\0" \ | 318 | "run fileload\0" \ |
320 | "scriptboot=echo Running ${mmcscriptfile} from mmc " \ | 319 | "scriptboot=echo Running ${mmcscriptfile} from mmc " \ |
321 | "${mmcnum}:${mmcpart} ...; source ${scriptaddr}\0" \ | 320 | "${mmcnum}:${mmcpart} ...; source ${scriptaddr}\0" \ |
322 | "kernboot=echo Booting ${mmckernfile} from mmc " \ | 321 | "kernboot=echo Booting ${mmckernfile} from mmc " \ |
323 | "${mmcnum}:${mmcpart} ...; bootm ${kernaddr}\0" \ | 322 | "${mmcnum}:${mmcpart} ...; bootm ${kernaddr}\0" \ |
324 | "kerninitrdboot=echo Booting ${mmckernfile} ${mmcinitrdfile} from mmc "\ | 323 | "kerninitrdboot=echo Booting ${mmckernfile} ${mmcinitrdfile} from mmc "\ |
325 | "${mmcnum}:${mmcpart} ...; bootm ${kernaddr} ${initrdaddr}\0" \ | 324 | "${mmcnum}:${mmcpart} ...; bootm ${kernaddr} ${initrdaddr}\0" \ |
326 | "attachboot=echo Booting attached kernel image ...;" \ | 325 | "attachboot=echo Booting attached kernel image ...;" \ |
327 | "setenv setup_omap_atag 1;" \ | 326 | "setenv setup_omap_atag 1;" \ |
328 | "bootm ${attkernaddr};" \ | 327 | "bootm ${attkernaddr};" \ |
329 | "setenv setup_omap_atag\0" \ | 328 | "setenv setup_omap_atag\0" \ |
330 | "trymmcscriptboot=if run switchmmc; then " \ | 329 | "trymmcscriptboot=if run switchmmc; then " \ |
331 | "if run scriptload; then " \ | 330 | "if run scriptload; then " \ |
332 | "run scriptboot;" \ | 331 | "run scriptboot;" \ |
333 | "fi;" \ | 332 | "fi;" \ |
334 | "fi\0" \ | 333 | "fi\0" \ |
335 | "trymmckernboot=if run switchmmc; then " \ | 334 | "trymmckernboot=if run switchmmc; then " \ |
336 | "if run kernload; then " \ | 335 | "if run kernload; then " \ |
337 | "run kernboot;" \ | 336 | "run kernboot;" \ |
338 | "fi;" \ | 337 | "fi;" \ |
339 | "fi\0" \ | 338 | "fi\0" \ |
340 | "trymmckerninitrdboot=if run switchmmc; then " \ | 339 | "trymmckerninitrdboot=if run switchmmc; then " \ |
341 | "if run initrdload; then " \ | 340 | "if run initrdload; then " \ |
342 | "if run kernload; then " \ | 341 | "if run kernload; then " \ |
343 | "run kerninitrdboot;" \ | 342 | "run kerninitrdboot;" \ |
344 | "fi;" \ | 343 | "fi;" \ |
345 | "fi; " \ | 344 | "fi; " \ |
346 | "fi\0" \ | 345 | "fi\0" \ |
347 | "trymmcpartboot=setenv mmcscriptfile boot.scr; run trymmcscriptboot;" \ | 346 | "trymmcpartboot=setenv mmcscriptfile boot.scr; run trymmcscriptboot;" \ |
348 | "setenv mmckernfile uImage; run trymmckernboot\0" \ | 347 | "setenv mmckernfile uImage; run trymmckernboot\0" \ |
349 | "trymmcallpartboot=setenv mmcpart 1; run trymmcpartboot;" \ | 348 | "trymmcallpartboot=setenv mmcpart 1; run trymmcpartboot;" \ |
350 | "setenv mmcpart 2; run trymmcpartboot;" \ | 349 | "setenv mmcpart 2; run trymmcpartboot;" \ |
351 | "setenv mmcpart 3; run trymmcpartboot;" \ | 350 | "setenv mmcpart 3; run trymmcpartboot;" \ |
352 | "setenv mmcpart 4; run trymmcpartboot\0" \ | 351 | "setenv mmcpart 4; run trymmcpartboot\0" \ |
353 | "trymmcboot=if run switchmmc; then " \ | 352 | "trymmcboot=if run switchmmc; then " \ |
354 | "setenv mmctype fat;" \ | 353 | "setenv mmctype fat;" \ |
355 | "run trymmcallpartboot;" \ | 354 | "run trymmcallpartboot;" \ |
356 | "setenv mmctype ext2;" \ | 355 | "setenv mmctype ext2;" \ |
357 | "run trymmcallpartboot;" \ | 356 | "run trymmcallpartboot;" \ |
358 | "setenv mmctype ext4;" \ | 357 | "setenv mmctype ext4;" \ |
359 | "run trymmcallpartboot;" \ | 358 | "run trymmcallpartboot;" \ |
360 | "fi\0" \ | 359 | "fi\0" \ |
361 | "emmcboot=setenv mmcnum 1; run trymmcboot\0" \ | 360 | "emmcboot=setenv mmcnum 1; run trymmcboot\0" \ |
362 | "sdboot=setenv mmcnum 0; run trymmcboot\0" \ | 361 | "sdboot=setenv mmcnum 0; run trymmcboot\0" \ |
362 | "menucmd=bootmenu\0" \ | ||
363 | "bootmenu_0=Attached kernel=run attachboot\0" \ | ||
364 | "bootmenu_1=Internal eMMC=run emmcboot\0" \ | ||
365 | "bootmenu_2=External SD card=run sdboot\0" \ | ||
366 | "bootmenu_3=U-Boot boot order=boot\0" \ | ||
367 | "bootmenu_delay=30\0" \ | ||
363 | "" | 368 | "" |
364 | 369 | ||
365 | #define CONFIG_PREBOOT \ | 370 | #define CONFIG_PREBOOT \ |
366 | "if run slide; then true; else run attachboot; fi;" \ | 371 | "setenv mmcnum 1; setenv mmcpart 1;" \ |
372 | "setenv mmcscriptfile bootmenu.scr;" \ | ||
373 | "if run switchmmc; then " \ | ||
374 | "setenv mmcdone true;" \ | ||
375 | "setenv mmctype fat;" \ | ||
376 | "if run scriptload; then true; else " \ | ||
377 | "setenv mmctype ext2;" \ | ||
378 | "if run scriptload; then true; else " \ | ||
379 | "setenv mmctype ext4;" \ | ||
380 | "if run scriptload; then true; else " \ | ||
381 | "setenv mmcdone false;" \ | ||
382 | "fi;" \ | ||
383 | "fi;" \ | ||
384 | "fi;" \ | ||
385 | "if ${mmcdone}; then " \ | ||
386 | "run scriptboot;" \ | ||
387 | "fi;" \ | ||
388 | "fi;" \ | ||
389 | "if run slide; then true; else " \ | ||
390 | "setenv bootmenu_delay 0;" \ | ||
391 | "setenv bootdelay 0;" \ | ||
392 | "fi" | ||
393 | |||
394 | #define CONFIG_POSTBOOTMENU \ | ||
395 | "echo;" \ | ||
367 | "echo Extra commands:;" \ | 396 | "echo Extra commands:;" \ |
368 | "echo run sercon - Use serial port for control.;" \ | 397 | "echo run sercon - Use serial port for control.;" \ |
369 | "echo run usbcon - Use usbtty for control.;" \ | 398 | "echo run usbcon - Use usbtty for control.;" \ |
370 | "echo run vgacon - Use framebuffer/keyboard.;" \ | 399 | "echo run vgacon - Use framebuffer/keyboard.;" \ |
371 | "echo run sdboot - Boot from SD card slot.;" \ | 400 | "echo run sdboot - Boot from SD card slot.;" \ |
372 | "echo run emmcboot - Boot internal eMMC memory.;" \ | 401 | "echo run emmcboot - Boot internal eMMC memory.;" \ |
373 | "echo run attachboot - Boot attached kernel image.;" \ | 402 | "echo run attachboot - Boot attached kernel image.;" \ |
374 | "echo" | 403 | "echo" |
375 | 404 | ||
376 | #define CONFIG_BOOTCOMMAND \ | 405 | #define CONFIG_BOOTCOMMAND \ |
377 | "run sdboot;" \ | 406 | "run sdboot;" \ |
378 | "run emmcboot;" \ | 407 | "run emmcboot;" \ |
379 | "run attachboot;" \ | 408 | "run attachboot;" \ |
380 | "echo" | 409 | "echo" |
410 | |||
411 | #define CONFIG_BOOTDELAY 30 | ||
412 | #define CONFIG_AUTOBOOT_KEYED | ||
413 | #define CONFIG_MENU | ||
414 | #define CONFIG_MENU_SHOW | ||
381 | 415 | ||
382 | /* | 416 | /* |
383 | * Miscellaneous configurable options | 417 | * Miscellaneous configurable options |
384 | */ | 418 | */ |
385 | #define CONFIG_SYS_LONGHELP /* undef to save memory */ | 419 | #define CONFIG_SYS_LONGHELP /* undef to save memory */ |
386 | #define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ | 420 | #define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ |
387 | #define CONFIG_SYS_PROMPT_HUSH_PS2 "> " | 421 | #define CONFIG_SYS_PROMPT_HUSH_PS2 "> " |
388 | #define CONFIG_SYS_PROMPT "Nokia RX-51 # " | 422 | #define CONFIG_SYS_PROMPT "Nokia RX-51 # " |
389 | #define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ | 423 | #define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ |
390 | /* Print Buffer Size */ | 424 | /* Print Buffer Size */ |
391 | #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ | 425 | #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ |
392 | sizeof(CONFIG_SYS_PROMPT) + 16) | 426 | sizeof(CONFIG_SYS_PROMPT) + 16) |
393 | #define CONFIG_SYS_MAXARGS 16 /* max number of command args */ | 427 | #define CONFIG_SYS_MAXARGS 16 /* max number of command args */ |
394 | /* Boot Argument Buffer Size */ | 428 | /* Boot Argument Buffer Size */ |
395 | #define CONFIG_SYS_BARGSIZE (CONFIG_SYS_CBSIZE) | 429 | #define CONFIG_SYS_BARGSIZE (CONFIG_SYS_CBSIZE) |
396 | 430 | ||
397 | #define CONFIG_SYS_MEMTEST_START (OMAP34XX_SDRC_CS0) | 431 | #define CONFIG_SYS_MEMTEST_START (OMAP34XX_SDRC_CS0) |
398 | #define CONFIG_SYS_MEMTEST_END (OMAP34XX_SDRC_CS0 + 0x01F00000)/*31MB*/ | 432 | #define CONFIG_SYS_MEMTEST_END (OMAP34XX_SDRC_CS0 + 0x01F00000)/*31MB*/ |
399 | 433 | ||
400 | /* default load address */ | 434 | /* default load address */ |
401 | #define CONFIG_SYS_LOAD_ADDR (OMAP34XX_SDRC_CS0) | 435 | #define CONFIG_SYS_LOAD_ADDR (OMAP34XX_SDRC_CS0) |
402 | 436 | ||
403 | /* | 437 | /* |
404 | * OMAP3 has 12 GP timers, they can be driven by the system clock | 438 | * OMAP3 has 12 GP timers, they can be driven by the system clock |
405 | * (12/13/16.8/19.2/38.4MHz) or by 32KHz clock. We use 13MHz (V_SCLK). | 439 | * (12/13/16.8/19.2/38.4MHz) or by 32KHz clock. We use 13MHz (V_SCLK). |
406 | * This rate is divided by a local divisor. | 440 | * This rate is divided by a local divisor. |
407 | */ | 441 | */ |
408 | #define CONFIG_SYS_TIMERBASE (OMAP34XX_GPT2) | 442 | #define CONFIG_SYS_TIMERBASE (OMAP34XX_GPT2) |
409 | #define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */ | 443 | #define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */ |
410 | #define CONFIG_SYS_HZ 1000 | 444 | #define CONFIG_SYS_HZ 1000 |
411 | 445 | ||
412 | /* | 446 | /* |
413 | * Stack sizes | 447 | * Stack sizes |
414 | * | 448 | * |
415 | * The stack sizes are set up in start.S using the settings below | 449 | * The stack sizes are set up in start.S using the settings below |
416 | */ | 450 | */ |
417 | #define CONFIG_STACKSIZE (128 << 10) /* regular stack 128 KiB */ | 451 | #define CONFIG_STACKSIZE (128 << 10) /* regular stack 128 KiB */ |
418 | 452 | ||
419 | /* | 453 | /* |
420 | * Physical Memory Map | 454 | * Physical Memory Map |
421 | */ | 455 | */ |
422 | #define CONFIG_NR_DRAM_BANKS 2 | 456 | #define CONFIG_NR_DRAM_BANKS 2 |
423 | #define PHYS_SDRAM_1 OMAP34XX_SDRC_CS0 | 457 | #define PHYS_SDRAM_1 OMAP34XX_SDRC_CS0 |
424 | 458 | ||
425 | /* | 459 | /* |
426 | * FLASH and environment organization | 460 | * FLASH and environment organization |
427 | */ | 461 | */ |
428 | 462 | ||
429 | #define CONFIG_ENV_IS_NOWHERE | 463 | #define CONFIG_ENV_IS_NOWHERE |
430 | 464 | ||
431 | #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 | 465 | #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 |
432 | #define CONFIG_SYS_INIT_RAM_ADDR 0x4020f800 | 466 | #define CONFIG_SYS_INIT_RAM_ADDR 0x4020f800 |
433 | #define CONFIG_SYS_INIT_RAM_SIZE 0x800 | 467 | #define CONFIG_SYS_INIT_RAM_SIZE 0x800 |
434 | #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ | 468 | #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ |
435 | CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) | 469 | CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) |
436 | 470 | ||
437 | /* | 471 | /* |
438 | * Attached kernel image | 472 | * Attached kernel image |
439 | */ | 473 | */ |
440 | 474 | ||
441 | #define SDRAM_SIZE 0x10000000 /* 256 MB */ | 475 | #define SDRAM_SIZE 0x10000000 /* 256 MB */ |
442 | #define SDRAM_END (CONFIG_SYS_SDRAM_BASE + SDRAM_SIZE) | 476 | #define SDRAM_END (CONFIG_SYS_SDRAM_BASE + SDRAM_SIZE) |
443 | 477 | ||
444 | #define IMAGE_MAXSIZE 0x1FF800 /* 2 MB - 2 kB */ | 478 | #define IMAGE_MAXSIZE 0x1FF800 /* 2 MB - 2 kB */ |
445 | #define KERNEL_OFFSET 0x40000 /* 256 kB */ | 479 | #define KERNEL_OFFSET 0x40000 /* 256 kB */ |
446 | #define KERNEL_MAXSIZE (IMAGE_MAXSIZE-KERNEL_OFFSET) | 480 | #define KERNEL_MAXSIZE (IMAGE_MAXSIZE-KERNEL_OFFSET) |
447 | #define KERNEL_ADDRESS (SDRAM_END-KERNEL_MAXSIZE) | 481 | #define KERNEL_ADDRESS (SDRAM_END-KERNEL_MAXSIZE) |
448 | 482 | ||
449 | /* Reserve protected RAM for attached kernel */ | 483 | /* Reserve protected RAM for attached kernel */ |
450 | #define CONFIG_PRAM ((KERNEL_MAXSIZE >> 10)+1) | 484 | #define CONFIG_PRAM ((KERNEL_MAXSIZE >> 10)+1) |
451 | 485 |
include/menu.h
1 | /* | 1 | /* |
2 | * Copyright 2010-2011 Calxeda, Inc. | 2 | * Copyright 2010-2011 Calxeda, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 5 | * under the terms of the GNU General Public License as published by the Free |
6 | * Software Foundation; either version 2 of the License, or (at your option) | 6 | * Software Foundation; either version 2 of the License, or (at your option) |
7 | * any later version. | 7 | * any later version. |
8 | * | 8 | * |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along with | 14 | * You should have received a copy of the GNU General Public License along with |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef __MENU_H__ | 18 | #ifndef __MENU_H__ |
19 | #define __MENU_H__ | 19 | #define __MENU_H__ |
20 | 20 | ||
21 | struct menu; | 21 | struct menu; |
22 | 22 | ||
23 | struct menu *menu_create(char *title, int timeout, int prompt, | 23 | struct menu *menu_create(char *title, int timeout, int prompt, |
24 | void (*item_data_print)(void *)); | 24 | void (*item_data_print)(void *), |
25 | char *(*item_choice)(void *), | ||
26 | void *item_choice_data); | ||
25 | int menu_default_set(struct menu *m, char *item_key); | 27 | int menu_default_set(struct menu *m, char *item_key); |
26 | int menu_get_choice(struct menu *m, void **choice); | 28 | int menu_get_choice(struct menu *m, void **choice); |
27 | int menu_item_add(struct menu *m, char *item_key, void *item_data); | 29 | int menu_item_add(struct menu *m, char *item_key, void *item_data); |
28 | int menu_destroy(struct menu *m); | 30 | int menu_destroy(struct menu *m); |
29 | void menu_display_statusline(struct menu *m); | 31 | void menu_display_statusline(struct menu *m); |
32 | int menu_default_choice(struct menu *m, void **choice); | ||
30 | 33 | ||
31 | #if defined(CONFIG_MENU_SHOW) | 34 | #if defined(CONFIG_MENU_SHOW) |
32 | int menu_show(int bootdelay); | 35 | int menu_show(int bootdelay); |
33 | #endif | 36 | #endif |
34 | #endif /* __MENU_H__ */ | 37 | #endif /* __MENU_H__ */ |
35 | 38 |