summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2009-03-20 22:50:08 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2009-03-20 22:50:08 +0000
commitc7b6ad5fdf3e89b5c68e2448dc360c6838a3b241 (patch)
tree169fb5693cbf0f3d3e992cfc291f00a82a034cc7
parent56086db778f35262122a778ea26ccf39d1034302 (diff)
downloadrockbox-c7b6ad5fdf3e89b5c68e2448dc360c6838a3b241.tar.gz
rockbox-c7b6ad5fdf3e89b5c68e2448dc360c6838a3b241.zip
Make Jz4740 USB tools a bit more configurable by letting you choose what file you want to upload when doing usbtool 10
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20415 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--utils/jz4740_tools/Makefile46
-rw-r--r--utils/jz4740_tools/README3
-rw-r--r--utils/jz4740_tools/jz4740_usbtool.c178
3 files changed, 117 insertions, 110 deletions
diff --git a/utils/jz4740_tools/Makefile b/utils/jz4740_tools/Makefile
index 3b1061b87a..f40adaa3e4 100644
--- a/utils/jz4740_tools/Makefile
+++ b/utils/jz4740_tools/Makefile
@@ -3,42 +3,52 @@ WIN_LIBUSB_INCLUDE_DIR = "$(WIN_DRIVERS_LIBUSB_DIR)\include"
3WIN_LIBUSB_LIB_DIR = "$(WIN_DRIVERS_LIBUSB_DIR)\lib\gcc" 3WIN_LIBUSB_LIB_DIR = "$(WIN_DRIVERS_LIBUSB_DIR)\lib\gcc"
4 4
5CFLAGS=-Wall 5CFLAGS=-Wall
6CC=gcc
6 7
7linux: usbtool HXFmerge HXFreplace HXFsplit IHFSsplit HXF2IHFS DLanalyser 8linux: usbtool HXFmerge HXFreplace HXFsplit IHFSsplit HXF2IHFS DLanalyser
8win: usbtool_win HXFmerge_win HXFsplit_win HXFreplace_win IHFSsplit_win HXF2IHFS_win DLanalyser_win 9win: usbtool_win HXFmerge_win HXFsplit_win HXFreplace_win IHFSsplit_win HXF2IHFS_win DLanalyser_win
9 10
10usbtool: 11bin2c: ../../rbutil/sansapatcher/bin2c.c
11 $(CC) $(CFLAGS) -o usbtool jz4740_usbtool.c -lusb 12 $(CC) $(CFLAGS) -o bin2c ../../rbutil/sansapatcher/bin2c.c
12usbtool_win:
13 $(CC) $(CFLAGS) -o usbtool.exe jz4740_usbtool.c -lusb -I $(WIN_LIBUSB_INCLUDE_DIR) -L $(WIN_LIBUSB_LIB_DIR)
14 13
15HXFmerge: 14bin2c.exe: ../../rbutil/sansapatcher/bin2c.c
15 $(CC) $(CFLAGS) -o bin2c.exe ../../rbutil/sansapatcher/bin2c.c
16
17jz_xloader.c: jz_xloader.bin
18 ./bin2c jz_xloader.bin jz_xloader
19
20usbtool: jz4740_usbtool.c bin2c jz_xloader.c
21 $(CC) $(CFLAGS) -o usbtool jz4740_usbtool.c jz_xloader.c -lusb
22usbtool_win: jz4740_usbtool.c bin2c.exe jz_xloader.c
23 $(CC) $(CFLAGS) -o usbtool.exe jz4740_usbtool.c jz_xloader.c -lusb -I $(WIN_LIBUSB_INCLUDE_DIR) -L $(WIN_LIBUSB_LIB_DIR)
24
25HXFmerge: HXFmerge.c
16 $(CC) $(CFLAGS) -o HXFmerge HXFmerge.c 26 $(CC) $(CFLAGS) -o HXFmerge HXFmerge.c
17HXFreplace: 27HXFreplace: HXFreplace.c
18 $(CC) $(CFLAGS) -o HXFreplace HXFreplace.c 28 $(CC) $(CFLAGS) -o HXFreplace HXFreplace.c
19HXFsplit: 29HXFsplit: HXFsplit.c
20 $(CC) $(CFLAGS) -o HXFsplit HXFsplit.c 30 $(CC) $(CFLAGS) -o HXFsplit HXFsplit.c
21IHFSsplit: 31IHFSsplit: IHFSsplit.c
22 $(CC) $(CFLAGS) -o IHFSsplit IHFSsplit.c 32 $(CC) $(CFLAGS) -o IHFSsplit IHFSsplit.c
23HXF2IHFS: 33HXF2IHFS: HXF2IHFS.c
24 $(CC) $(CFLAGS) -o HXF2IHFS HXF2IHFS.c 34 $(CC) $(CFLAGS) -o HXF2IHFS HXF2IHFS.c
25DLanalyser: 35DLanalyser: DLanalyser.c
26 $(CC) $(CFLAGS) -o DLanalyser DLanalyser.c 36 $(CC) $(CFLAGS) -o DLanalyser DLanalyser.c
27 37
28HXFmerge_win: 38HXFmerge_win: HXFmerge.c
29 $(CC) $(CFLAGS) -o HXFmerge.exe HXFmerge.c 39 $(CC) $(CFLAGS) -o HXFmerge.exe HXFmerge.c
30HXFreplace_win: 40HXFreplace_win: HXFreplace.c
31 $(CC) $(CFLAGS) -o HXFreplace.exe HXFreplace.c 41 $(CC) $(CFLAGS) -o HXFreplace.exe HXFreplace.c
32HXFsplit_win: 42HXFsplit_win: HXFsplit.c
33 $(CC) $(CFLAGS) -o HXFsplit.exe HXFsplit.c 43 $(CC) $(CFLAGS) -o HXFsplit.exe HXFsplit.c
34IHFSsplit_win: 44IHFSsplit_win: IHFSsplit.c
35 $(CC) $(CFLAGS) -o IHFSsplit.exe IHFSsplit.c 45 $(CC) $(CFLAGS) -o IHFSsplit.exe IHFSsplit.c
36HXF2IHFS_win: 46HXF2IHFS_win: HXF2IHFS.c
37 $(CC) $(CFLAGS) -o HXF2IHFS.exe HXF2IHFS.c 47 $(CC) $(CFLAGS) -o HXF2IHFS.exe HXF2IHFS.c
38 DLanalyser_win: 48DLanalyser_win: DLanalyser.c
39 $(CC) $(CFLAGS) -o DLanalyser.exe DLanalyser.c 49 $(CC) $(CFLAGS) -o DLanalyser.exe DLanalyser.c
40 50
41clean-linux: 51clean-linux:
42 rm HXFmerge HXFreplace HXFsplit usbtool IHFSsplit HXF2IHFS DLanalyser 52 rm HXFmerge HXFreplace HXFsplit usbtool IHFSsplit HXF2IHFS DLanalyser bin2c
43clean-win: 53clean-win:
44 del HXFmerge.exe HXFreplace.exe HXFsplit.exe usbtool.exe IHFSsplit.exe HXF2IHFS.exe DLanalyser.exe 54 del HXFmerge.exe HXFreplace.exe HXFsplit.exe usbtool.exe IHFSsplit.exe HXF2IHFS.exe DLanalyser.exe bin2c.exe
diff --git a/utils/jz4740_tools/README b/utils/jz4740_tools/README
index d6a64d81e5..75c0dc1d05 100644
--- a/utils/jz4740_tools/README
+++ b/utils/jz4740_tools/README
@@ -5,6 +5,9 @@
5 Copyright (C) 2008 5 Copyright (C) 2008
6******************************************************************************* 6*******************************************************************************
7 7
8To compile usbtools, you'll need jz_xloader (which can be get at
9http://repo.or.cz/w/jz_xloader.git).
10
8When you're on Linux, just type "make linux" to compile all the utilities (make 11When you're on Linux, just type "make linux" to compile all the utilities (make
9sure you have libusb-dev installed). 12sure you have libusb-dev installed).
10For cleaning: "make clean-linux" 13For cleaning: "make clean-linux"
diff --git a/utils/jz4740_tools/jz4740_usbtool.c b/utils/jz4740_tools/jz4740_usbtool.c
index 1fdb8f4d46..904d64790f 100644
--- a/utils/jz4740_tools/jz4740_usbtool.c
+++ b/utils/jz4740_tools/jz4740_usbtool.c
@@ -35,9 +35,10 @@
35#include <sys/stat.h> 35#include <sys/stat.h>
36#include <unistd.h> 36#include <unistd.h>
37#include <fcntl.h> 37#include <fcntl.h>
38#include "jz4740.h"
39#include <stdbool.h> 38#include <stdbool.h>
40#include <unistd.h> 39#include <unistd.h>
40#include "jz4740.h"
41#include "jz_xloader.h"
41 42
42#define VERSION "0.4" 43#define VERSION "0.4"
43 44
@@ -120,12 +121,28 @@ enum OPTION
120int filesize(FILE* fd) 121int filesize(FILE* fd)
121{ 122{
122 int ret; 123 int ret;
124
123 fseek(fd, 0, SEEK_END); 125 fseek(fd, 0, SEEK_END);
124 ret = ftell(fd); 126 ret = ftell(fd);
125 fseek(fd, 0, SEEK_SET); 127 fseek(fd, 0, SEEK_SET);
128
126 return ret; 129 return ret;
127} 130}
128 131
132bool file_exists(const char* filename)
133{
134 FILE* fp = fopen(filename, "r");
135
136 if(fp)
137 {
138 fclose(fp);
139 return true;
140 }
141 else
142 return false;
143}
144
145
129#define SEND_COMMAND(cmd, arg) err = usb_control_msg(dh, USB_ENDPOINT_OUT | USB_TYPE_VENDOR, (cmd), (arg)>>16, (arg)&0xFFFF, NULL, 0, TOUT);\ 146#define SEND_COMMAND(cmd, arg) err = usb_control_msg(dh, USB_ENDPOINT_OUT | USB_TYPE_VENDOR, (cmd), (arg)>>16, (arg)&0xFFFF, NULL, 0, TOUT);\
130 if (err < 0) \ 147 if (err < 0) \
131 { \ 148 { \
@@ -155,8 +172,7 @@ int filesize(FILE* fd)
155 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); \ 172 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); \
156 return -1; \ 173 return -1; \
157 } 174 }
158 175int upload_data(usb_dev_handle* dh, int address, unsigned char* p, int len)
159int upload_app(usb_dev_handle* dh, int address, unsigned char* p, int len, bool stage2)
160{ 176{
161 int err; 177 int err;
162 char buf[9]; 178 char buf[9];
@@ -166,11 +182,6 @@ int upload_app(usb_dev_handle* dh, int address, unsigned char* p, int len, bool
166 GET_CPU_INFO(buf); 182 GET_CPU_INFO(buf);
167 buf[8] = 0; 183 buf[8] = 0;
168 fprintf(stderr, "%s\n", buf); 184 fprintf(stderr, "%s\n", buf);
169#if 0
170 fprintf(stderr, "[INFO] Flushing cache...");
171 SEND_COMMAND(VR_FLUSH_CACHES, 0);
172 fprintf(stderr, " Done!\n");
173#endif
174 185
175 fprintf(stderr, "[INFO] SET_DATA_ADDRESS to 0x%x...", address); 186 fprintf(stderr, "[INFO] SET_DATA_ADDRESS to 0x%x...", address);
176 SEND_COMMAND(VR_SET_DATA_ADDRESS, address); 187 SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
@@ -196,12 +207,32 @@ int upload_app(usb_dev_handle* dh, int address, unsigned char* p, int len, bool
196 else 207 else
197 fprintf(stderr, " Done!\n"); 208 fprintf(stderr, " Done!\n");
198 free(tmp_buf); 209 free(tmp_buf);
210
211 return 0;
212}
199 213
200 fprintf(stderr, "[INFO] Booting device [STAGE%d]...", (stage2 ? 2 : 1)); 214int boot(usb_dev_handle* dh, int address, bool stage2)
215{
216 int err;
217
218 fprintf(stderr, "[INFO] Booting device STAGE%d...", (stage2 ? 2 : 1));
201 SEND_COMMAND((stage2 ? VR_PROGRAM_START2 : VR_PROGRAM_START1), address ); 219 SEND_COMMAND((stage2 ? VR_PROGRAM_START2 : VR_PROGRAM_START1), address );
202 fprintf(stderr, " Done!\n"); 220 fprintf(stderr, " Done!\n");
203 221
204 return 0; 222 return err;
223}
224
225int upload_app(usb_dev_handle* dh, int address, unsigned char* p, int len, bool stage2)
226{
227 int err = upload_data(dh, address, p, len);
228 if(err == 0)
229 {
230 err = boot(dh, address, stage2);
231 if(err == 0)
232 fprintf(stderr, "[INFO] Done!\n");
233 }
234
235 return err;
205} 236}
206 237
207int read_data(usb_dev_handle* dh, int address, unsigned char *p, int len) 238int read_data(usb_dev_handle* dh, int address, unsigned char *p, int len)
@@ -313,46 +344,6 @@ int test_device(usb_dev_handle* dh)
313 return 0; 344 return 0;
314} 345}
315 346
316#define VOL_DOWN (1 << 27)
317#define VOL_UP (1 << 0)
318#define MENU (1 << 1)
319#define HOLD (1 << 16)
320#define OFF (1 << 29)
321#define MASK (VOL_DOWN|VOL_UP|MENU|HOLD|OFF)
322#define TS_MASK (SADC_STATE_PEND|SADC_STATE_PENU|SADC_STATE_TSRDY)
323int probe_device(usb_dev_handle* dh)
324{
325 int tmp;
326
327 while(1)
328 {
329 if(read_reg(dh, SADC_STATE, 1) & SADC_STATE_TSRDY)
330 {
331 printf("%x\n", read_reg(dh, SADC_TSDAT, 4));
332 or_reg(dh, SADC_CTRL, read_reg(dh, SADC_STATE, 1) & TS_MASK, 1);
333 }
334
335 tmp = read_reg(dh, GPIO_PXPIN(3), 4);
336 if(tmp < 0)
337 return tmp;
338 if(tmp ^ MASK)
339 {
340 if(!(tmp & VOL_DOWN))
341 printf("VOL_DOWN\t");
342 if(!(tmp & VOL_UP))
343 printf("VOL_UP\t");
344 if(!(tmp & MENU))
345 printf("MENU\t");
346 if(!(tmp & OFF))
347 printf("OFF\t");
348 if(!(tmp & HOLD))
349 printf("HOLD\t");
350 printf("\n");
351 }
352 }
353 return 0;
354}
355
356unsigned int read_file(const char *name, unsigned char **buffer) 347unsigned int read_file(const char *name, unsigned char **buffer)
357{ 348{
358 FILE *fd; 349 FILE *fd;
@@ -508,30 +499,33 @@ int mimic_of(usb_dev_handle *dh, bool vx767)
508 return 0; 499 return 0;
509} 500}
510 501
511int send_rockbox(usb_dev_handle *dh) 502int send_rockbox(usb_dev_handle *dh, const char* filename)
512{ 503{
513 int err, fsize; 504 int fsize;
514 unsigned char *buffer, *buffer2; 505 unsigned char *buffer;
515 char cpu[8];
516 506
517 fprintf(stderr, "[INFO] Start!\n"); 507 fprintf(stderr, "[INFO] Start!\n");
518 _GET_CPU; 508 if(file_exists("jz_xloader.bin"))
519 _SET_ADDR(0x8000 << 16); 509 {
520 _SEND_FILE("1.bin"); 510 fprintf(stderr, "[INFO] Using jz_xloader.bin\n");
521 _GET_CPU; 511 fsize = read_file("jz_xloader.bin", &buffer);
522 _VERIFY_DATA("1.bin", 0x8000 << 16); 512 upload_data(dh, 0x080000000, buffer, fsize);
523 _STAGE1(0x8000 << 16); 513 free(buffer);
524 _SLEEP(3); 514 }
525 _GET_CPU; 515 else
526 _SET_ADDR(0x080004000); 516 {
527 _SEND_FILE("onda.bin"); 517 fprintf(stderr, "[INFO] Using built-in jz_xloader.bin\n");
528 _GET_CPU; 518 upload_data(dh, 0x080000000, jz_xloader, LEN_jz_xloader);
529 _VERIFY_DATA("onda.bin", 0x080004000); 519 }
530 _GET_CPU; 520 boot(dh, 0x080000000, false);
531 _FLUSH; 521
532 _GET_CPU; 522 fsize = read_file(filename, &buffer);
533 _STAGE2(0x080004008); 523 upload_data(dh, 0x080004000, buffer, fsize);
524 free(buffer);
525 boot(dh, 0x080004000, true);
526
534 fprintf(stderr, "[INFO] Done!\n"); 527 fprintf(stderr, "[INFO] Done!\n");
528
535 return 0; 529 return 0;
536} 530}
537 531
@@ -558,7 +552,6 @@ int nand_dump(usb_dev_handle *dh)
558 fclose(fd); 552 fclose(fd);
559 return 0; 553 return 0;
560 } 554 }
561 memset(buffer, 0, LENGTH);
562 555
563 SEND_NAND_COMMAND(0, NAND_INIT, 0); 556 SEND_NAND_COMMAND(0, NAND_INIT, 0);
564 /* 557 /*
@@ -595,9 +588,8 @@ int nand_dump(usb_dev_handle *dh)
595 588
596 return n; 589 return n;
597} 590}
598#undef LENGTH
599 591
600#define LENGTH 0x1000*16 592#define ROM_LENGTH 0x1000*16
601int rom_dump(usb_dev_handle *dh) 593int rom_dump(usb_dev_handle *dh)
602{ 594{
603 int err; 595 int err;
@@ -612,21 +604,20 @@ int rom_dump(usb_dev_handle *dh)
612 return 0; 604 return 0;
613 } 605 }
614 606
615 buffer = (unsigned char*)malloc(LENGTH); 607 buffer = (unsigned char*)malloc(ROM_LENGTH);
616 if (buffer == NULL) 608 if (buffer == NULL)
617 { 609 {
618 fprintf(stderr, "[ERR] Could not allocate memory.\n"); 610 fprintf(stderr, "[ERR] Could not allocate memory.\n");
619 fclose(fd); 611 fclose(fd);
620 return 0; 612 return 0;
621 } 613 }
622 memset(buffer, 0, LENGTH);
623 614
624 SEND_COMMAND(VR_SET_DATA_ADDRESS, 0x1FC00000); 615 SEND_COMMAND(VR_SET_DATA_ADDRESS, 0x1FC00000);
625 SEND_COMMAND(VR_SET_DATA_LENGTH, LENGTH); 616 SEND_COMMAND(VR_SET_DATA_LENGTH, ROM_LENGTH);
626 617
627 fprintf(stderr, "[INFO] Reading data...\n"); 618 fprintf(stderr, "[INFO] Reading data...\n");
628 err = usb_bulk_read(dh, USB_ENDPOINT_IN | EP_BULK_TO, (char*)buffer, LENGTH, TOUT); 619 err = usb_bulk_read(dh, USB_ENDPOINT_IN | EP_BULK_TO, (char*)buffer, ROM_LENGTH, TOUT);
629 if (err != LENGTH) 620 if (err != ROM_LENGTH)
630 { 621 {
631 fprintf(stderr,"\n[ERR] Error writing data\n"); 622 fprintf(stderr,"\n[ERR] Error writing data\n");
632 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); 623 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
@@ -635,8 +626,8 @@ int rom_dump(usb_dev_handle *dh)
635 return -1; 626 return -1;
636 } 627 }
637 628
638 n = fwrite(buffer, 1, LENGTH, fd); 629 n = fwrite(buffer, 1, ROM_LENGTH, fd);
639 if (n != LENGTH) 630 if (n != ROM_LENGTH)
640 { 631 {
641 fprintf(stderr, "[ERR] Short write.\n"); 632 fprintf(stderr, "[ERR] Short write.\n");
642 fclose(fd); 633 fclose(fd);
@@ -736,9 +727,6 @@ found:
736 case 3: 727 case 3:
737 err = test_device(dh); 728 err = test_device(dh);
738 break; 729 break;
739 case 4:
740 err = probe_device(dh);
741 break;
742 case 6: 730 case 6:
743 case 7: 731 case 7:
744 err = mimic_of(dh, (func == 7)); 732 err = mimic_of(dh, (func == 7));
@@ -750,7 +738,7 @@ found:
750 err = rom_dump(dh); 738 err = rom_dump(dh);
751 break; 739 break;
752 case 10: 740 case 10:
753 err = send_rockbox(dh); 741 err = send_rockbox(dh, buf);
754 break; 742 break;
755 } 743 }
756 744
@@ -775,13 +763,12 @@ void print_usage(void)
775 fprintf(stderr, "\t\t 1 -> upload file to specified address and boot from it\n"); 763 fprintf(stderr, "\t\t 1 -> upload file to specified address and boot from it\n");
776 fprintf(stderr, "\t\t 2 -> read data from [ADDRESS] with length [LEN] to [FILE]\n"); 764 fprintf(stderr, "\t\t 2 -> read data from [ADDRESS] with length [LEN] to [FILE]\n");
777 fprintf(stderr, "\t\t 3 -> read device status\n"); 765 fprintf(stderr, "\t\t 3 -> read device status\n");
778 fprintf(stderr, "\t\t 4 -> probe keys (only Onda VX747)\n");
779 fprintf(stderr, "\t\t 5 -> same as 1 but do a stage 2 boot\n"); 766 fprintf(stderr, "\t\t 5 -> same as 1 but do a stage 2 boot\n");
780 fprintf(stderr, "\t\t 6 -> mimic VX747 OF fw recovery\n"); 767 fprintf(stderr, "\t\t 6 -> mimic VX747 OF fw recovery\n");
781 fprintf(stderr, "\t\t 7 -> mimic VX767 OF fw recovery\n"); 768 fprintf(stderr, "\t\t 7 -> mimic VX767 OF fw recovery\n");
782 fprintf(stderr, "\t\t 8 -> do a NAND dump\n"); 769 fprintf(stderr, "\t\t 8 -> do a NAND dump\n");
783 fprintf(stderr, "\t\t 9 -> do a ROM dump\n"); 770 fprintf(stderr, "\t\t 9 -> do a ROM dump\n");
784 fprintf(stderr, "\t\t10 -> send Rockbox bootloader to SDRAM\n"); 771 fprintf(stderr, "\t\t10 -> send Rockbox bootloader at [FILE] to SDRAM\n");
785 772
786#ifdef _WIN32 773#ifdef _WIN32
787 fprintf(stderr, "\nExample:\n\t usbtool.exe 1 fw.bin 0x80000000\n"); 774 fprintf(stderr, "\nExample:\n\t usbtool.exe 1 fw.bin 0x80000000\n");
@@ -855,7 +842,6 @@ int main(int argc, char* argv[])
855 fprintf(stderr, "[INFO] File size: %d bytes\n", n); 842 fprintf(stderr, "[INFO] File size: %d bytes\n", n);
856 843
857 return jzconnect(address, buf, len, cmd); 844 return jzconnect(address, buf, len, cmd);
858 break;
859 case 2: 845 case 2:
860 if (sscanf(argv[3], "0x%x", &address) <= 0) 846 if (sscanf(argv[3], "0x%x", &address) <= 0)
861 { 847 {
@@ -892,20 +878,28 @@ int main(int argc, char* argv[])
892 fclose(fd); 878 fclose(fd);
893 879
894 return err; 880 return err;
895 break; 881 case 10:
882 if(argc < 3)
883 {
884 print_usage();
885 return 1;
886 }
887
888 if(!file_exists(argv[2]))
889 {
890 print_usage();
891 return 1;
892 }
893 return jzconnect(address, argv[2], 0, 10);
896 case 3: 894 case 3:
897 case 4:
898 case 6: 895 case 6:
899 case 7: 896 case 7:
900 case 8: 897 case 8:
901 case 9: 898 case 9:
902 case 10:
903 return jzconnect(address, NULL, 0, cmd); 899 return jzconnect(address, NULL, 0, cmd);
904 break;
905 default: 900 default:
906 print_usage(); 901 print_usage();
907 return 1; 902 return 1;
908 break;
909 } 903 }
910 904
911 return 0; 905 return 0;