1 /*
2  * (C) Copyright 2002
3  * Richard Jones, rjones@nexus-tech.net
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  * Boot support
26  */
27 #include <common.h>
28 #include <command.h>
29 #include <s_record.h>
30 #include <net.h>
31 #include <ata.h>
32 #include <part.h>
33 #include <fat.h>
34 
35 
do_fat_fsload(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])36 int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
37 {
38 	long size;
39 	unsigned long offset;
40 	unsigned long count;
41 	char buf [12];
42 	block_dev_desc_t *dev_desc=NULL;
43 	int dev=0;
44 	int part=1;
45 	char *ep;
46 
47 	if (argc < 5) {
48 		printf ("usage: fatload <interface> <dev[:part]> <addr> <filename> [bytes]\n");
49 		return 1;
50 	}
51 	dev = (int)simple_strtoul (argv[2], &ep, 16);
52 	dev_desc=get_dev(argv[1],dev);
53 	if (dev_desc==NULL) {
54 		puts ("\n** Invalid boot device **\n");
55 		return 1;
56 	}
57 	if (*ep) {
58 		if (*ep != ':') {
59 			puts ("\n** Invalid boot device, use `dev[:part]' **\n");
60 			return 1;
61 		}
62 		part = (int)simple_strtoul(++ep, NULL, 16);
63 	}
64 	if (fat_register_device(dev_desc,part)!=0) {
65 		printf ("\n** Unable to use %s %d:%d for fatload **\n",argv[1],dev,part);
66 		return 1;
67 	}
68 	offset = simple_strtoul (argv[3], NULL, 16);
69 	if (argc == 6)
70 		count = simple_strtoul (argv[5], NULL, 16);
71 	else
72 		count = 0;
73 	size = file_fat_read (argv[4], (unsigned char *) offset, count);
74 
75 	if(size==-1) {
76 		printf("\n** Unable to read \"%s\" from %s %d:%d **\n",argv[4],argv[1],dev,part);
77 		return 1;
78 	}
79 
80 	printf ("\n%ld bytes read\n", size);
81 
82 	sprintf(buf, "%lX", size);
83 	setenv("filesize", buf);
84 
85 	return 0;
86 }
87 
88 
89 U_BOOT_CMD(
90 	fatload,	6,	0,	do_fat_fsload,
91 	"load binary file from a dos filesystem",
92 	"<interface> <dev[:part]>  <addr> <filename> [bytes]\n"
93 	"    - load binary file 'filename' from 'dev' on 'interface'\n"
94 	"      to address 'addr' from dos filesystem"
95 );
96 
do_fat_ls(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])97 int do_fat_ls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
98 {
99 	char *filename = "/";
100 	int ret;
101 	int dev=0;
102 	int part=1;
103 	char *ep;
104 	block_dev_desc_t *dev_desc=NULL;
105 
106 	if (argc < 3) {
107 		printf ("usage: fatls <interface> <dev[:part]> [directory]\n");
108 		return (0);
109 	}
110 	dev = (int)simple_strtoul (argv[2], &ep, 16);
111 	dev_desc=get_dev(argv[1],dev);
112 	if (dev_desc==NULL) {
113 		puts ("\n** Invalid boot device **\n");
114 		return 1;
115 	}
116 	if (*ep) {
117 		if (*ep != ':') {
118 			puts ("\n** Invalid boot device, use `dev[:part]' **\n");
119 			return 1;
120 		}
121 		part = (int)simple_strtoul(++ep, NULL, 16);
122 	}
123 	if (fat_register_device(dev_desc,part)!=0) {
124 		printf ("\n** Unable to use %s %d:%d for fatls **\n",argv[1],dev,part);
125 		return 1;
126 	}
127 	if (argc == 4)
128 		ret = file_fat_ls (argv[3]);
129 	else
130 		ret = file_fat_ls (filename);
131 
132 	if(ret!=0)
133 		printf("No Fat FS detected\n");
134 	return (ret);
135 }
136 
137 U_BOOT_CMD(
138 	fatls,	4,	1,	do_fat_ls,
139 	"list files in a directory (default /)",
140 	"<interface> <dev[:part]> [directory]\n"
141 	"    - list files from 'dev' on 'interface' in a 'directory'"
142 );
143 
do_fat_fsinfo(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])144 int do_fat_fsinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
145 {
146 	int dev=0;
147 	int part=1;
148 	char *ep;
149 	block_dev_desc_t *dev_desc=NULL;
150 
151 	if (argc < 2) {
152 		printf ("usage: fatinfo <interface> <dev[:part]>\n");
153 		return (0);
154 	}
155 	dev = (int)simple_strtoul (argv[2], &ep, 16);
156 	dev_desc=get_dev(argv[1],dev);
157 	if (dev_desc==NULL) {
158 		puts ("\n** Invalid boot device **\n");
159 		return 1;
160 	}
161 	if (*ep) {
162 		if (*ep != ':') {
163 			puts ("\n** Invalid boot device, use `dev[:part]' **\n");
164 			return 1;
165 		}
166 		part = (int)simple_strtoul(++ep, NULL, 16);
167 	}
168 	if (fat_register_device(dev_desc,part)!=0) {
169 		printf ("\n** Unable to use %s %d:%d for fatinfo **\n",argv[1],dev,part);
170 		return 1;
171 	}
172 	return (file_fat_detectfs ());
173 }
174 
175 U_BOOT_CMD(
176 	fatinfo,	3,	1,	do_fat_fsinfo,
177 	"print information about filesystem",
178 	"<interface> <dev[:part]>\n"
179 	"    - print information about filesystem from 'dev' on 'interface'"
180 );
181 
182 #ifdef NOT_IMPLEMENTED_YET
183 /* find first device whose first partition is a DOS filesystem */
find_fat_partition(void)184 int find_fat_partition (void)
185 {
186 	int i, j;
187 	block_dev_desc_t *dev_desc;
188 	unsigned char *part_table;
189 	unsigned char buffer[ATA_BLOCKSIZE];
190 
191 	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; i++) {
192 		dev_desc = ide_get_dev (i);
193 		if (!dev_desc) {
194 			debug ("couldn't get ide device!\n");
195 			return (-1);
196 		}
197 		if (dev_desc->part_type == PART_TYPE_DOS) {
198 			if (dev_desc->
199 				block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) {
200 				debug ("can't perform block_read!\n");
201 				return (-1);
202 			}
203 			part_table = &buffer[0x1be];	/* start with partition #4 */
204 			for (j = 0; j < 4; j++) {
205 				if ((part_table[4] == 1 ||	/* 12-bit FAT */
206 				     part_table[4] == 4 ||	/* 16-bit FAT */
207 				     part_table[4] == 6) &&	/* > 32Meg part */
208 				    part_table[0] == 0x80) {	/* bootable? */
209 					curr_dev = i;
210 					part_offset = part_table[11];
211 					part_offset <<= 8;
212 					part_offset |= part_table[10];
213 					part_offset <<= 8;
214 					part_offset |= part_table[9];
215 					part_offset <<= 8;
216 					part_offset |= part_table[8];
217 					debug ("found partition start at %ld\n", part_offset);
218 					return (0);
219 				}
220 				part_table += 16;
221 			}
222 		}
223 	}
224 
225 	debug ("no valid devices found!\n");
226 	return (-1);
227 }
228 
229 int
do_fat_dump(cmd_tbl_t * cmdtp,bd_t * bd,int flag,int argc,char * argv[])230 do_fat_dump (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
231 {
232 	__u8 block[1024];
233 	int ret;
234 	int bknum;
235 
236 	ret = 0;
237 
238 	if (argc != 2) {
239 		printf ("needs an argument!\n");
240 		return (0);
241 	}
242 
243 	bknum = simple_strtoul (argv[1], NULL, 10);
244 
245 	if (disk_read (0, bknum, block) != 0) {
246 		printf ("Error: reading block\n");
247 		return -1;
248 	}
249 	printf ("FAT dump: %d\n", bknum);
250 	hexdump (512, block);
251 
252 	return (ret);
253 }
254 
disk_read(__u32 startblock,__u32 getsize,__u8 * bufptr)255 int disk_read (__u32 startblock, __u32 getsize, __u8 *bufptr)
256 {
257 	ulong tot;
258 	block_dev_desc_t *dev_desc;
259 
260 	if (curr_dev < 0) {
261 		if (find_fat_partition () != 0)
262 			return (-1);
263 	}
264 
265 	dev_desc = ide_get_dev (curr_dev);
266 	if (!dev_desc) {
267 		debug ("couldn't get ide device\n");
268 		return (-1);
269 	}
270 
271 	tot = dev_desc->block_read (0, startblock + part_offset,
272 				    getsize, (ulong *) bufptr);
273 
274 	/* should we do this here?
275 	   flush_cache ((ulong)buf, cnt*ide_dev_desc[device].blksz);
276 	 */
277 
278 	if (tot == getsize)
279 		return (0);
280 
281 	debug ("unable to read from device!\n");
282 
283 	return (-1);
284 }
285 
286 
isprint(unsigned char ch)287 static int isprint (unsigned char ch)
288 {
289 	if (ch >= 32 && ch < 127)
290 		return (1);
291 
292 	return (0);
293 }
294 
295 
hexdump(int cnt,unsigned char * data)296 void hexdump (int cnt, unsigned char *data)
297 {
298 	int i;
299 	int run;
300 	int offset;
301 
302 	offset = 0;
303 	while (cnt) {
304 		printf ("%04X : ", offset);
305 		if (cnt >= 16)
306 			run = 16;
307 		else
308 			run = cnt;
309 		cnt -= run;
310 		for (i = 0; i < run; i++)
311 			printf ("%02X ", (unsigned int) data[i]);
312 		printf (": ");
313 		for (i = 0; i < run; i++)
314 			printf ("%c", isprint (data[i]) ? data[i] : '.');
315 		printf ("\n");
316 		data = &data[16];
317 		offset += run;
318 	}
319 }
320 #endif	/* NOT_IMPLEMENTED_YET */
321