1/*******************************************************************************
2 *
3 *  Copyright (C) 2009-2011 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/*****************************************************************************
20**
21**  Name:          brcm_patchram_plus.c
22**
23**  Description:   This program downloads a patchram files in the HCD format
24**                 to Broadcom Bluetooth based silicon and combo chips and
25**				   and other utility functions.
26**
27**                 It can be invoked from the command line in the form
28**						<-d> to print a debug log
29**						<--patchram patchram_file>
30**						<--baudrate baud_rate>
31**						<--bd_addr bd_address>
32**						<--enable_lpm>
33**						<--enable_hci>
34**						<--use_baudrate_for_download>
35**						<--scopcm=sco_routing,pcm_interface_rate,frame_type,
36**							sync_mode,clock_mode,lsb_first,fill_bits,
37**							fill_method,fill_num,right_justify>
38**
39**							Where
40**
41**							sco_routing is 0 for PCM, 1 for Transport,
42**							2 for Codec and 3 for I2S,
43**
44**							pcm_interface_rate is 0 for 128KBps, 1 for
45**							256 KBps, 2 for 512KBps, 3 for 1024KBps,
46**							and 4 for 2048Kbps,
47**
48**							frame_type is 0 for short and 1 for long,
49**
50**							sync_mode is 0 for slave and 1 for master,
51**
52**							clock_mode is 0 for slabe and 1 for master,
53**
54**							lsb_first is 0 for false aand 1 for true,
55**
56**							fill_bits is the value in decimal for unused bits,
57**
58**							fill_method is 0 for 0's and 1 for 1's, 2 for
59**								signed and 3 for programmable,
60**
61**							fill_num is the number or bits to fill,
62**
63**							right_justify is 0 for false and 1 for true
64**
65**						<--i2s=i2s_enable,is_master,sample_rate,clock_rate>
66**
67**							Where
68**
69**							i2s_enable is 0 for disable and 1 for enable,
70**
71**							is_master is 0 for slave and 1 for master,
72**
73**							sample_rate is 0 for 8KHz, 1 for 16Khz and
74**								2 for 4 KHz,
75**
76**							clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for
77**								1024 KHz and 4 for 2048 KHz.
78**
79**						<--no2bytes skips waiting for two byte confirmation
80**							before starting patchram download. Newer chips
81**                          do not generate these two bytes.>
82**						<--tosleep=number of microsseconds to sleep before
83**							patchram download begins.>
84**						uart_device_name
85**
86**                 For example:
87**
88**                 brcm_patchram_plus -d --patchram  \
89**						BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
90**
91**                 It will return 0 for success and a number greater than 0
92**                 for any errors.
93**
94**                 For Android, this program invoked using a
95**                 "system(2)" call from the beginning of the bt_enable
96**                 function inside the file
97**                 system/bluetooth/bluedroid/bluetooth.c.
98**
99**                 If the Android system property "ro.bt.bcm_bdaddr_path" is
100**                 set, then the bd_addr will be read from this path.
101**                 This is overridden by --bd_addr on the command line.
102**
103******************************************************************************/
104
105// TODO: Integrate BCM support into Bluez hciattach
106
107#include <stdio.h>
108#include <getopt.h>
109#include <errno.h>
110
111#include <sys/types.h>
112#include <sys/stat.h>
113#include <fcntl.h>
114
115#include <stdlib.h>
116
117#ifdef ANDROID
118#include <termios.h>
119#else
120#include <sys/termios.h>
121#include <sys/ioctl.h>
122#include <limits.h>
123#endif
124
125#include <string.h>
126#include <signal.h>
127
128#ifdef ANDROID
129#include <cutils/properties.h>
130#define LOG_TAG "brcm_patchram_plus"
131#include <cutils/log.h>
132#undef printf
133#define printf ALOGD
134#undef fprintf
135#define fprintf(x, ...) \
136  { if(x==stderr) ALOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); }
137
138#endif //ANDROID
139
140#ifndef N_HCI
141#define N_HCI	15
142#endif
143
144#define HCIUARTSETPROTO		_IOW('U', 200, int)
145#define HCIUARTGETPROTO		_IOR('U', 201, int)
146#define HCIUARTGETDEVICE	_IOR('U', 202, int)
147
148#define HCI_UART_H4		0
149#define HCI_UART_BCSP	1
150#define HCI_UART_3WIRE	2
151#define HCI_UART_H4DS	3
152#define HCI_UART_LL		4
153
154typedef unsigned char uchar;
155
156int uart_fd = -1;
157int hcdfile_fd = -1;
158int termios_baudrate = 0;
159int bdaddr_flag = 0;
160int enable_lpm = 0;
161int enable_hci = 0;
162int use_baudrate_for_download = 0;
163int debug = 0;
164int scopcm = 0;
165int i2s = 0;
166int no2bytes = 0;
167int tosleep = 0;
168
169struct termios termios;
170uchar buffer[1024];
171
172uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
173
174uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
175
176uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
177	0x00, 0x00, 0x00, 0x00 };
178
179uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
180	0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
181
182uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
183	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
184	0x00, 0x00 };
185
186uchar hci_write_sco_pcm_int[] =
187	{ 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
188
189uchar hci_write_pcm_data_format[] =
190	{ 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
191
192uchar hci_write_i2spcm_interface_param[] =
193	{ 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 };
194
195int
196parse_patchram(char *optarg)
197{
198	char *p;
199
200	if (!(p = strrchr(optarg, '.'))) {
201		fprintf(stderr, "file %s not an HCD file\n", optarg);
202		exit(3);
203	}
204
205	p++;
206
207	if (strcasecmp("hcd", p) != 0) {
208		fprintf(stderr, "file %s not an HCD file\n", optarg);
209		exit(4);
210	}
211
212	if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
213		fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
214		exit(5);
215	}
216
217	return(0);
218}
219
220void
221BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud)
222{
223	if(baud_rate == 0 || encoded_baud == NULL) {
224		fprintf(stderr, "Baudrate not supported!");
225		return;
226	}
227
228	encoded_baud[3] = (uchar)(baud_rate >> 24);
229	encoded_baud[2] = (uchar)(baud_rate >> 16);
230	encoded_baud[1] = (uchar)(baud_rate >> 8);
231	encoded_baud[0] = (uchar)(baud_rate & 0xFF);
232}
233
234typedef struct {
235	int baud_rate;
236	int termios_value;
237} tBaudRates;
238
239tBaudRates baud_rates[] = {
240	{ 115200, B115200 },
241	{ 230400, B230400 },
242	{ 460800, B460800 },
243	{ 500000, B500000 },
244	{ 576000, B576000 },
245	{ 921600, B921600 },
246	{ 1000000, B1000000 },
247	{ 1152000, B1152000 },
248	{ 1500000, B1500000 },
249	{ 2000000, B2000000 },
250	{ 2500000, B2500000 },
251	{ 3000000, B3000000 },
252#ifndef __CYGWIN__
253	{ 3500000, B3500000 },
254	{ 4000000, B4000000 }
255#endif
256};
257
258int
259validate_baudrate(int baud_rate, int *value)
260{
261	unsigned int i;
262
263	for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
264		if (baud_rates[i].baud_rate == baud_rate) {
265			*value = baud_rates[i].termios_value;
266			return(1);
267		}
268	}
269
270	return(0);
271}
272
273int
274parse_baudrate(char *optarg)
275{
276	int baudrate = atoi(optarg);
277
278	if (validate_baudrate(baudrate, &termios_baudrate)) {
279		BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
280	}
281
282	return(0);
283}
284
285int
286parse_bdaddr(char *optarg)
287{
288	int bd_addr[6];
289	int i;
290
291	sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
292		&bd_addr[5], &bd_addr[4], &bd_addr[3],
293		&bd_addr[2], &bd_addr[1], &bd_addr[0]);
294
295	for (i = 0; i < 6; i++) {
296		hci_write_bd_addr[4 + i] = bd_addr[i];
297	}
298
299	bdaddr_flag = 1;
300
301	return(0);
302}
303
304int
305parse_enable_lpm(char *optarg)
306{
307	enable_lpm = 1;
308	return(0);
309}
310
311int
312parse_use_baudrate_for_download(char *optarg)
313{
314	use_baudrate_for_download = 1;
315	return(0);
316}
317
318int
319parse_enable_hci(char *optarg)
320{
321	enable_hci = 1;
322	return(0);
323}
324
325int
326parse_scopcm(char *optarg)
327{
328	int param[10];
329	int ret;
330	int i;
331
332	ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
333		&param[0], &param[1], &param[2], &param[3], &param[4],
334		&param[5], &param[6], &param[7], &param[8], &param[9]);
335
336	if (ret != 10) {
337		return(1);
338	}
339
340	scopcm = 1;
341
342	for (i = 0; i < 5; i++) {
343		hci_write_sco_pcm_int[4 + i] = param[i];
344	}
345
346	for (i = 0; i < 5; i++) {
347		hci_write_pcm_data_format[4 + i] = param[5 + i];
348	}
349
350	return(0);
351}
352
353int
354parse_i2s(char *optarg)
355{
356	int param[4];
357	int ret;
358	int i;
359
360	ret = sscanf(optarg, "%d,%d,%d,%d", &param[0], &param[1], &param[2],
361		&param[3]);
362
363	if (ret != 4) {
364		return(1);
365	}
366
367	i2s = 1;
368
369	for (i = 0; i < 4; i++) {
370		hci_write_i2spcm_interface_param[4 + i] = param[i];
371	}
372
373	return(0);
374}
375
376int
377parse_no2bytes(char *optarg)
378{
379	no2bytes = 1;
380	return(0);
381}
382
383int
384parse_tosleep(char *optarg)
385{
386	tosleep = atoi(optarg);
387
388	if (tosleep <= 0) {
389		return(1);
390	}
391
392	return(0);
393}
394
395void
396usage(char *argv0)
397{
398	printf("Usage %s:\n", argv0);
399	printf("\t<-d> to print a debug log\n");
400	printf("\t<--patchram patchram_file>\n");
401	printf("\t<--baudrate baud_rate>\n");
402	printf("\t<--bd_addr bd_address>\n");
403	printf("\t<--enable_lpm>\n");
404	printf("\t<--enable_hci>\n");
405	printf("\t<--use_baudrate_for_download> - Uses the\n");
406	printf("\t\tbaudrate for downloading the firmware\n");
407	printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n");
408	printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n");
409	printf("\t\tfill_method,fill_num,right_justify>\n");
410	printf("\n\t\tWhere\n");
411	printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n");
412	printf("\t\t2 for Codec and 3 for I2S,\n");
413	printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n");
414	printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n");
415	printf("\t\tand 4 for 2048Kbps,\n");
416	printf("\n\t\tframe_type is 0 for short and 1 for long,\n");
417	printf("\t\tsync_mode is 0 for slave and 1 for master,\n");
418	printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n");
419	printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n");
420	printf("\n\t\tfill_bits is the value in decimal for unused bits,\n");
421	printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n");
422	printf("\t\tsigned and 3 for programmable,\n");
423	printf("\n\t\tfill_num is the number or bits to fill,\n");
424	printf("\n\t\tright_justify is 0 for false and 1 for true\n");
425	printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n");
426	printf("\n\t\tWhere\n");
427	printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n");
428	printf("\n\t\tis_master is 0 for slave and 1 for master,\n");
429	printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n");
430	printf("\t\t2 for 4 KHz,\n");
431	printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n");
432	printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n");
433	printf("\t<--no2bytes skips waiting for two byte confirmation\n");
434	printf("\t\tbefore starting patchram download. Newer chips\n");
435	printf("\t\tdo not generate these two bytes.>\n");
436	printf("\t<--tosleep=microseconds>\n");
437	printf("\tuart_device_name\n");
438}
439
440int
441parse_cmd_line(int argc, char **argv)
442{
443	int c;
444	int ret = 0;
445
446	typedef int (*PFI)();
447
448	PFI parse[] = { parse_patchram, parse_baudrate,
449		parse_bdaddr, parse_enable_lpm, parse_enable_hci,
450		parse_use_baudrate_for_download,
451		parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep};
452
453	while (1) {
454		int this_option_optind = optind ? optind : 1;
455		int option_index = 0;
456
457		static struct option long_options[] = {
458			{"patchram", 1, 0, 0},
459			{"baudrate", 1, 0, 0},
460			{"bd_addr", 1, 0, 0},
461			{"enable_lpm", 0, 0, 0},
462			{"enable_hci", 0, 0, 0},
463			{"use_baudrate_for_download", 0, 0, 0},
464			{"scopcm", 1, 0, 0},
465			{"i2s", 1, 0, 0},
466			{"no2bytes", 0, 0, 0},
467			{"tosleep", 1, 0, 0},
468			{0, 0, 0, 0}
469		};
470
471		c = getopt_long_only (argc, argv, "d", long_options,
472				&option_index);
473
474		if (c == -1) {
475			break;
476		}
477
478		switch (c) {
479			case 0:
480				if (debug) {
481					printf ("option %s",
482						long_options[option_index].name);
483					if (optarg)
484						printf (" with arg %s", optarg);
485					printf ("\n");
486				}
487
488				ret = (*parse[option_index])(optarg);
489
490				break;
491			case 'd':
492				debug = 1;
493				break;
494
495			case '?':
496				//nobreak
497			default:
498				usage(argv[0]);
499				break;
500		}
501
502		if (ret) {
503			usage(argv[0]);
504			break;
505		}
506	}
507
508	if (ret) {
509		return(1);
510	}
511
512	if (optind < argc) {
513		if (debug)
514			printf ("%s \n", argv[optind]);
515		if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
516			fprintf(stderr, "port %s could not be opened, error %d\n",
517					argv[2], errno);
518		}
519	}
520
521	return(0);
522}
523
524void
525init_uart()
526{
527	tcflush(uart_fd, TCIOFLUSH);
528	tcgetattr(uart_fd, &termios);
529
530#ifndef __CYGWIN__
531	cfmakeraw(&termios);
532#else
533	termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
534                | INLCR | IGNCR | ICRNL | IXON);
535	termios.c_oflag &= ~OPOST;
536	termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
537	termios.c_cflag &= ~(CSIZE | PARENB);
538	termios.c_cflag |= CS8;
539#endif
540
541	termios.c_cflag |= CRTSCTS;
542	tcsetattr(uart_fd, TCSANOW, &termios);
543	tcflush(uart_fd, TCIOFLUSH);
544	tcsetattr(uart_fd, TCSANOW, &termios);
545	tcflush(uart_fd, TCIOFLUSH);
546	tcflush(uart_fd, TCIOFLUSH);
547	cfsetospeed(&termios, B115200);
548	cfsetispeed(&termios, B115200);
549	tcsetattr(uart_fd, TCSANOW, &termios);
550}
551
552void
553dump(uchar *out, int len)
554{
555	int i;
556
557	for (i = 0; i < len; i++) {
558		if (i && !(i % 16)) {
559			fprintf(stderr, "\n");
560		}
561
562		fprintf(stderr, "%02x ", out[i]);
563	}
564
565	fprintf(stderr, "\n");
566}
567
568void
569read_event(int fd, uchar *buffer)
570{
571	int i = 0;
572	int len = 3;
573	int count;
574
575	while ((count = read(fd, &buffer[i], len)) < len) {
576		i += count;
577		len -= count;
578	}
579
580	i += count;
581	len = buffer[2];
582
583	while ((count = read(fd, &buffer[i], len)) < len) {
584		i += count;
585		len -= count;
586	}
587
588	if (debug) {
589		count += i;
590
591		fprintf(stderr, "received %d\n", count);
592		dump(buffer, count);
593	}
594}
595
596void
597hci_send_cmd(uchar *buf, int len)
598{
599	if (debug) {
600		fprintf(stderr, "writing\n");
601		dump(buf, len);
602	}
603
604	write(uart_fd, buf, len);
605}
606
607void
608expired(int sig)
609{
610	hci_send_cmd(hci_reset, sizeof(hci_reset));
611	alarm(4);
612}
613
614void
615proc_reset()
616{
617	signal(SIGALRM, expired);
618
619
620	hci_send_cmd(hci_reset, sizeof(hci_reset));
621
622	alarm(4);
623
624	read_event(uart_fd, buffer);
625
626	alarm(0);
627}
628
629void
630proc_patchram()
631{
632	int len;
633
634	hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
635
636	read_event(uart_fd, buffer);
637
638	if (!no2bytes) {
639		read(uart_fd, &buffer[0], 2);
640	}
641
642	if (tosleep) {
643		usleep(tosleep);
644	}
645
646	while (read(hcdfile_fd, &buffer[1], 3)) {
647		buffer[0] = 0x01;
648
649		len = buffer[3];
650
651		read(hcdfile_fd, &buffer[4], len);
652
653		hci_send_cmd(buffer, len + 4);
654
655		read_event(uart_fd, buffer);
656	}
657
658	if (use_baudrate_for_download) {
659		cfsetospeed(&termios, B115200);
660		cfsetispeed(&termios, B115200);
661		tcsetattr(uart_fd, TCSANOW, &termios);
662	}
663	proc_reset();
664}
665
666void
667proc_baudrate()
668{
669	hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
670
671	read_event(uart_fd, buffer);
672
673	cfsetospeed(&termios, termios_baudrate);
674	cfsetispeed(&termios, termios_baudrate);
675	tcsetattr(uart_fd, TCSANOW, &termios);
676
677	if (debug) {
678		fprintf(stderr, "Done setting baudrate\n");
679	}
680}
681
682void
683proc_bdaddr()
684{
685	hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
686
687	read_event(uart_fd, buffer);
688}
689
690void
691proc_enable_lpm()
692{
693	hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
694
695	read_event(uart_fd, buffer);
696}
697
698void
699proc_scopcm()
700{
701	hci_send_cmd(hci_write_sco_pcm_int,
702		sizeof(hci_write_sco_pcm_int));
703
704	read_event(uart_fd, buffer);
705
706	hci_send_cmd(hci_write_pcm_data_format,
707		sizeof(hci_write_pcm_data_format));
708
709	read_event(uart_fd, buffer);
710}
711
712void
713proc_i2s()
714{
715	hci_send_cmd(hci_write_i2spcm_interface_param,
716		sizeof(hci_write_i2spcm_interface_param));
717
718	read_event(uart_fd, buffer);
719}
720
721void
722proc_enable_hci()
723{
724	int i = N_HCI;
725	int proto = HCI_UART_H4;
726	if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
727		fprintf(stderr, "Can't set line discipline\n");
728		return;
729	}
730
731	if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
732		fprintf(stderr, "Can't set hci protocol\n");
733		return;
734	}
735	fprintf(stderr, "Done setting line discpline\n");
736	return;
737}
738
739#ifdef ANDROID
740void
741read_default_bdaddr()
742{
743	int sz;
744	int fd;
745
746	char path[PROPERTY_VALUE_MAX];
747
748	char bdaddr[18];
749	int len = 17;
750	memset(bdaddr, 0, (len + 1) * sizeof(char));
751
752	property_get("ro.bt.bdaddr_path", path, "");
753	if (path[0] == 0)
754		return;
755
756	fd = open(path, O_RDONLY);
757	if (fd < 0) {
758		fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
759				errno);
760		return;
761	}
762
763	sz = read(fd, bdaddr, len);
764	if (sz < 0) {
765		fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
766				errno);
767		close(fd);
768		return;
769	} else if (sz != len) {
770		fprintf(stderr, "read(%s) unexpected size %d", path, sz);
771		close(fd);
772		return;
773	}
774
775	if (debug) {
776		printf("Read default bdaddr of %s\n", bdaddr);
777	}
778
779	parse_bdaddr(bdaddr);
780}
781#endif
782
783
784int
785main (int argc, char **argv)
786{
787#ifdef ANDROID
788	read_default_bdaddr();
789#endif
790
791	if (parse_cmd_line(argc, argv)) {
792		exit(1);
793	}
794
795	if (uart_fd < 0) {
796		exit(2);
797	}
798
799	init_uart();
800
801	proc_reset();
802
803	if (use_baudrate_for_download) {
804		if (termios_baudrate) {
805			proc_baudrate();
806		}
807	}
808
809	if (hcdfile_fd > 0) {
810		proc_patchram();
811	}
812
813	if (termios_baudrate) {
814		proc_baudrate();
815	}
816
817	if (bdaddr_flag) {
818		proc_bdaddr();
819	}
820
821	if (enable_lpm) {
822		proc_enable_lpm();
823	}
824
825	if (scopcm) {
826		proc_scopcm();
827	}
828
829	if (i2s) {
830		proc_i2s();
831	}
832
833	if (enable_hci) {
834		proc_enable_hci();
835
836		while (1) {
837			sleep(UINT_MAX);
838		}
839	}
840
841	exit(0);
842}
843