/******************************************************************************* * * Copyright (C) 2009-2011 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /***************************************************************************** ** ** Name: brcm_patchram_plus.c ** ** Description: This program downloads a patchram files in the HCD format ** to Broadcom Bluetooth based silicon and combo chips and ** and other utility functions. ** ** It can be invoked from the command line in the form ** <-d> to print a debug log ** <--patchram patchram_file> ** <--baudrate baud_rate> ** <--bd_addr bd_address> ** <--enable_lpm> ** <--enable_hci> ** <--use_baudrate_for_download> ** <--scopcm=sco_routing,pcm_interface_rate,frame_type, ** sync_mode,clock_mode,lsb_first,fill_bits, ** fill_method,fill_num,right_justify> ** ** Where ** ** sco_routing is 0 for PCM, 1 for Transport, ** 2 for Codec and 3 for I2S, ** ** pcm_interface_rate is 0 for 128KBps, 1 for ** 256 KBps, 2 for 512KBps, 3 for 1024KBps, ** and 4 for 2048Kbps, ** ** frame_type is 0 for short and 1 for long, ** ** sync_mode is 0 for slave and 1 for master, ** ** clock_mode is 0 for slabe and 1 for master, ** ** lsb_first is 0 for false aand 1 for true, ** ** fill_bits is the value in decimal for unused bits, ** ** fill_method is 0 for 0's and 1 for 1's, 2 for ** signed and 3 for programmable, ** ** fill_num is the number or bits to fill, ** ** right_justify is 0 for false and 1 for true ** ** <--i2s=i2s_enable,is_master,sample_rate,clock_rate> ** ** Where ** ** i2s_enable is 0 for disable and 1 for enable, ** ** is_master is 0 for slave and 1 for master, ** ** sample_rate is 0 for 8KHz, 1 for 16Khz and ** 2 for 4 KHz, ** ** clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for ** 1024 KHz and 4 for 2048 KHz. ** ** <--no2bytes skips waiting for two byte confirmation ** before starting patchram download. Newer chips ** do not generate these two bytes.> ** <--tosleep=number of microsseconds to sleep before ** patchram download begins.> ** uart_device_name ** ** For example: ** ** brcm_patchram_plus -d --patchram \ ** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0 ** ** It will return 0 for success and a number greater than 0 ** for any errors. ** ** For Android, this program invoked using a ** "system(2)" call from the beginning of the bt_enable ** function inside the file ** system/bluetooth/bluedroid/bluetooth.c. ** ** If the Android system property "ro.bt.bcm_bdaddr_path" is ** set, then the bd_addr will be read from this path. ** This is overridden by --bd_addr on the command line. ** ******************************************************************************/ // TODO: Integrate BCM support into Bluez hciattach #include #include #include #include #include #include #include #include #include #ifdef ANDROID #include #else #include #include #include #include #endif #include #include #ifdef ANDROID #include #define LOG_TAG "brcm_patchram_plus" #include #undef printf #define printf ALOGD #undef fprintf #define fprintf(x, ...) \ { if(x==stderr) ALOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); } #endif //ANDROID #ifndef N_HCI #define N_HCI 15 #endif #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) #define HCIUARTGETDEVICE _IOR('U', 202, int) #define AP_NAME_SUFFIX_LEN 18 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 #define HCI_UART_3WIRE 2 #define HCI_UART_H4DS 3 #define HCI_UART_LL 4 #define LOCAL_NAME_BUFFER_LEN 32 #define HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING 6 typedef unsigned char uchar; /* AMPAK FW auto detection table */ typedef struct { char *chip_id; char *updated_chip_id; } fw_auto_detection_entry_t; #define FW_TABLE_VERSION "v1.1 20161117" static const fw_auto_detection_entry_t fw_auto_detection_table[] = { {"4343A0","bcm43438a0"}, //AP6212 {"BCM43430A1","BCM43430A1"}, //AP6212A {"BCM20702A","BCM20710A1"}, //AP6210B {"BCM4335C0","bcm4339a0"}, //AP6335 {"BCM4330B1","BCM40183B2"}, //AP6330 {"BCM4324B3","BCM43241B4"}, //AP62X2 {"BCM4350C0","bcm4354a1"}, //AP6354 {"BCM4345C5","BCM4345C5"}, //AP6256 {"BCM4354A2","BCM4356A2"}, //AP6356 {"BCM4345C0","BCM4345C0"}, //AP6255 //{"BCM43341B0","BCM43341B0"}, //AP6234 //{"BCM2076B1","BCM2076B1"}, //AP6476 {"BCM43430B0","BCM4343B0"}, //AP6236 {"BCM4359C0","BCM4359C0"}, //AP6359 {"BCM4349B1","BCM4359B1"}, //AP6359 {"BCM4359C0","BCM4359C0"}, //AP6398s {(char *) NULL, NULL} }; int uart_fd = -1; int hcdfile_fd = -1; int termios_baudrate = 0; int bdaddr_flag = 0; int enable_lpm = 0; int enable_hci = 0; int use_baudrate_for_download = 0; int debug = 0; int scopcm = 0; int i2s = 0; int no2bytes = 0; int tosleep = 0; struct termios termios; uchar buffer[1024]; uchar local_name[LOCAL_NAME_BUFFER_LEN]; uchar fw_folder_path[1024]; uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 }; uchar hci_read_local_name[] = { 0x01, 0x14, 0x0c, 0x00 }; uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 }; uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; uchar hci_write_sco_pcm_int[] = { 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; uchar hci_write_pcm_data_format[] = { 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; uchar hci_write_i2spcm_interface_param[] = { 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 }; int parse_patchram(char *optarg) { int len = strlen(optarg); char *p = optarg+len-1;; /*Look for first '/' to know the fw path*/ while(len>0) { if(*p == '/') break; len--; p--; } if(len>0) { *p =0; strcpy(fw_folder_path,optarg); fprintf(stderr,"FW folder path = %s\n", fw_folder_path); } #if 0 char *p; if (!(p = strrchr(optarg, '.'))) { fprintf(stderr, "file %s not an HCD file\n", optarg); exit(3); } p++; if (strcasecmp("hcd", p) != 0) { fprintf(stderr, "file %s not an HCD file\n", optarg); exit(4); } if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) { fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno); exit(5); } #endif return(0); } void BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud) { if(baud_rate == 0 || encoded_baud == NULL) { fprintf(stderr, "Baudrate not supported!"); return; } encoded_baud[3] = (uchar)(baud_rate >> 24); encoded_baud[2] = (uchar)(baud_rate >> 16); encoded_baud[1] = (uchar)(baud_rate >> 8); encoded_baud[0] = (uchar)(baud_rate & 0xFF); } typedef struct { int baud_rate; int termios_value; } tBaudRates; tBaudRates baud_rates[] = { { 115200, B115200 }, { 230400, B230400 }, { 460800, B460800 }, { 500000, B500000 }, { 576000, B576000 }, { 921600, B921600 }, { 1000000, B1000000 }, { 1152000, B1152000 }, { 1500000, B1500000 }, { 2000000, B2000000 }, { 2500000, B2500000 }, { 3000000, B3000000 }, #ifndef __CYGWIN__ { 3500000, B3500000 }, { 4000000, B4000000 } #endif }; int validate_baudrate(int baud_rate, int *value) { unsigned int i; for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) { if (baud_rates[i].baud_rate == baud_rate) { *value = baud_rates[i].termios_value; return(1); } } return(0); } int parse_baudrate(char *optarg) { int baudrate = atoi(optarg); if (validate_baudrate(baudrate, &termios_baudrate)) { BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]); } return(0); } int parse_bdaddr(char *optarg) { int bd_addr[6]; int i; sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &bd_addr[5], &bd_addr[4], &bd_addr[3], &bd_addr[2], &bd_addr[1], &bd_addr[0]); for (i = 0; i < 6; i++) { hci_write_bd_addr[4 + i] = bd_addr[i]; } bdaddr_flag = 1; return(0); } int readApName(char *name, int len) { FILE* devInfo = NULL; if(len < AP_NAME_SUFFIX_LEN) { return -1; } devInfo = fopen("/data/cfg/device_info.txt","rb+"); if(devInfo) { fseek(devInfo, 36, SEEK_SET); fread(name, 1, AP_NAME_SUFFIX_LEN, devInfo); fclose(devInfo); // is default value or not if(0 == strncmp(name, "11:22:33:44:55:66", 17)) { return -1; } } else { return -1; } return 0; } int writeApName(const char* name, int len) { FILE* devInfo = NULL; char nameBuf[AP_NAME_SUFFIX_LEN] = {0}; if(len < 17) { return -1; } if(0 != strncmp(name, "11:22:33:44:55", 17)) { devInfo = fopen("/data/cfg/device_info.txt","rb+"); if(devInfo) { fseek(devInfo, 36, SEEK_SET); snprintf(nameBuf, AP_NAME_SUFFIX_LEN, "%s", name); fwrite(nameBuf, 1, AP_NAME_SUFFIX_LEN, devInfo); fflush(devInfo); fsync(fileno(devInfo)); fclose(devInfo); } system("cp /data/cfg/device_info.txt /data/cfg/device_info"); } } int parse_bdaddr_rand(char *optarg) { int bd_addr[6]; int i,j; char optargtest[18]; char mh[]=":"; char metachar[]="ABCDEF0123456789"; if(0 != readApName(optargtest,AP_NAME_SUFFIX_LEN)){ srand(time(NULL)); for(j=0;j<17;j++){ if(j%3 == 2){ optargtest[j]= mh[0]; }else{ optargtest[j] = metachar[rand()%16]; } } optargtest[17]='\0'; writeApName(optargtest,AP_NAME_SUFFIX_LEN); } sscanf(optargtest, "%02X:%02X:%02X:%02X:%02X:%02X", &bd_addr[5], &bd_addr[4], &bd_addr[3], &bd_addr[2], &bd_addr[1], &bd_addr[0]); for (i = 0; i < 6; i++) { hci_write_bd_addr[4 + i] = bd_addr[i]; } bdaddr_flag = 1; return(0); } int parse_enable_lpm(char *optarg) { enable_lpm = 1; return(0); } int parse_use_baudrate_for_download(char *optarg) { use_baudrate_for_download = 1; return(0); } int parse_enable_hci(char *optarg) { enable_hci = 1; return(0); } int parse_scopcm(char *optarg) { int param[10]; int ret; int i; ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", ¶m[0], ¶m[1], ¶m[2], ¶m[3], ¶m[4], ¶m[5], ¶m[6], ¶m[7], ¶m[8], ¶m[9]); if (ret != 10) { return(1); } scopcm = 1; for (i = 0; i < 5; i++) { hci_write_sco_pcm_int[4 + i] = param[i]; } for (i = 0; i < 5; i++) { hci_write_pcm_data_format[4 + i] = param[5 + i]; } return(0); } int parse_i2s(char *optarg) { int param[4]; int ret; int i; ret = sscanf(optarg, "%d,%d,%d,%d", ¶m[0], ¶m[1], ¶m[2], ¶m[3]); if (ret != 4) { return(1); } i2s = 1; for (i = 0; i < 4; i++) { hci_write_i2spcm_interface_param[4 + i] = param[i]; } return(0); } int parse_no2bytes(char *optarg) { no2bytes = 1; return(0); } int parse_tosleep(char *optarg) { tosleep = atoi(optarg); if (tosleep <= 0) { return(1); } return(0); } void usage(char *argv0) { printf("Usage %s:\n", argv0); printf("\t<-d> to print a debug log\n"); printf("\t<--patchram patchram_file>\n"); printf("\t<--baudrate baud_rate>\n"); printf("\t<--bd_addr bd_address>\n"); printf("\t<--enable_lpm>\n"); printf("\t<--enable_hci>\n"); printf("\t<--use_baudrate_for_download> - Uses the\n"); printf("\t\tbaudrate for downloading the firmware\n"); printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n"); printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n"); printf("\t\tfill_method,fill_num,right_justify>\n"); printf("\n\t\tWhere\n"); printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n"); printf("\t\t2 for Codec and 3 for I2S,\n"); printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n"); printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n"); printf("\t\tand 4 for 2048Kbps,\n"); printf("\n\t\tframe_type is 0 for short and 1 for long,\n"); printf("\t\tsync_mode is 0 for slave and 1 for master,\n"); printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n"); printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n"); printf("\n\t\tfill_bits is the value in decimal for unused bits,\n"); printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n"); printf("\t\tsigned and 3 for programmable,\n"); printf("\n\t\tfill_num is the number or bits to fill,\n"); printf("\n\t\tright_justify is 0 for false and 1 for true\n"); printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n"); printf("\n\t\tWhere\n"); printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n"); printf("\n\t\tis_master is 0 for slave and 1 for master,\n"); printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n"); printf("\t\t2 for 4 KHz,\n"); printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n"); printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n"); printf("\t<--no2bytes skips waiting for two byte confirmation\n"); printf("\t\tbefore starting patchram download. Newer chips\n"); printf("\t\tdo not generate these two bytes.>\n"); printf("\t<--tosleep=microseconds>\n"); printf("\tuart_device_name\n"); } int parse_cmd_line(int argc, char **argv) { int c; int ret = 0; typedef int (*PFI)(); PFI parse[] = { parse_patchram, parse_baudrate, parse_bdaddr,parse_bdaddr_rand, parse_enable_lpm, parse_enable_hci, parse_use_baudrate_for_download, parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep}; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"patchram", 1, 0, 0}, {"baudrate", 1, 0, 0}, {"bd_addr", 1, 0, 0}, {"bd_addr_rand", 0, 0, 0}, {"enable_lpm", 0, 0, 0}, {"enable_hci", 0, 0, 0}, {"use_baudrate_for_download", 0, 0, 0}, {"scopcm", 1, 0, 0}, {"i2s", 1, 0, 0}, {"no2bytes", 0, 0, 0}, {"tosleep", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only (argc, argv, "d", long_options, &option_index); if (c == -1) { break; } switch (c) { case 0: if (debug) { printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); } ret = (*parse[option_index])(optarg); break; case 'd': debug = 1; break; case '?': //nobreak default: usage(argv[0]); break; } if (ret) { usage(argv[0]); break; } } if (ret) { return(1); } if (optind < argc) { if (debug) printf ("%s \n", argv[optind]); if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) { fprintf(stderr, "port %s could not be opened, error %d\n", argv[2], errno); } } return(0); } void init_uart() { tcflush(uart_fd, TCIOFLUSH); tcgetattr(uart_fd, &termios); #ifndef __CYGWIN__ cfmakeraw(&termios); #else termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios.c_oflag &= ~OPOST; termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios.c_cflag &= ~(CSIZE | PARENB); termios.c_cflag |= CS8; #endif termios.c_cflag |= CRTSCTS; tcsetattr(uart_fd, TCSANOW, &termios); tcflush(uart_fd, TCIOFLUSH); tcsetattr(uart_fd, TCSANOW, &termios); tcflush(uart_fd, TCIOFLUSH); tcflush(uart_fd, TCIOFLUSH); cfsetospeed(&termios, B115200); cfsetispeed(&termios, B115200); tcsetattr(uart_fd, TCSANOW, &termios); } void dump(uchar *out, int len) { int i; for (i = 0; i < len; i++) { if (i && !(i % 16)) { fprintf(stderr, "\n"); } fprintf(stderr, "%02x ", out[i]); } fprintf(stderr, "\n"); } void read_event(int fd, uchar *buffer) { int i = 0; int len = 3; int count; while ((count = read(fd, &buffer[i], len)) < len) { i += count; len -= count; //fprintf(stderr, "received11 %d\n", count); } i += count; len = buffer[2]; //fprintf(stderr, "received22 %d\n", count); while ((count = read(fd, &buffer[i], len)) < len) { i += count; len -= count; } //fprintf(stderr, "received33 %d\n", count); if (debug) { count += i; fprintf(stderr, "received %d\n", count); dump(buffer, count); } } void hci_send_cmd(uchar *buf, int len) { if (debug) { fprintf(stderr, "writing\n"); dump(buf, len); } write(uart_fd, buf, len); } void expired(int sig) { hci_send_cmd(hci_reset, sizeof(hci_reset)); alarm(4); } void proc_reset() { signal(SIGALRM, expired); fprintf(stderr, "proc_reset"); hci_send_cmd(hci_reset, sizeof(hci_reset)); alarm(4); read_event(uart_fd, buffer); alarm(0); } void proc_read_local_name() { int i; char *p_name; hci_send_cmd(hci_read_local_name, sizeof(hci_read_local_name)); read_event(uart_fd, buffer); p_name = &buffer[1+HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING]; for (i=0; (i < LOCAL_NAME_BUFFER_LEN)||(*(p_name+i) != 0); i++) *(p_name+i) = toupper(*(p_name+i)); strcpy(local_name,p_name); fprintf(stderr,"chip id = %s\n", local_name); } void proc_open_patchram() { char fw_path[1024]; char *p; int i; fw_auto_detection_entry_t *p_entry; p_entry = (fw_auto_detection_entry_t *)fw_auto_detection_table; while (p_entry->chip_id != NULL) { if (strstr(local_name, p_entry->chip_id)!=NULL) { strcpy(local_name,p_entry->updated_chip_id); break; } p_entry++; } sprintf(fw_path,"%s/%s.hcd",fw_folder_path,local_name); fprintf(stderr, "FW path = %s\n", fw_path); if ((hcdfile_fd = open(fw_path, O_RDONLY)) == -1) { fprintf(stderr, "file %s could not be opened, error %d\n", fw_path , errno); p = local_name; fprintf(stderr, "Retry lower case FW name\n"); for (i=0; (i < LOCAL_NAME_BUFFER_LEN)||(*(p+i) != 0); i++) *(p+i) = tolower(*(p+i)); sprintf(fw_path,"%s/%s.hcd",fw_folder_path,local_name); fprintf(stderr, "FW path = %s\n", fw_path); if ((hcdfile_fd = open(fw_path, O_RDONLY)) == -1) { fprintf(stderr, "file %s could not be opened, error %d\n", fw_path, errno); exit(5); } } } void proc_patchram() { int len; hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver)); fprintf(stderr, "send hci_download_minidriver"); read_event(uart_fd, buffer); if (!no2bytes) { read(uart_fd, &buffer[0], 2); } if (tosleep) { usleep(tosleep); } while (read(hcdfile_fd, &buffer[1], 3)) { buffer[0] = 0x01; len = buffer[3]; read(hcdfile_fd, &buffer[4], len); hci_send_cmd(buffer, len + 4); read_event(uart_fd, buffer); } usleep(200000); if (use_baudrate_for_download) { cfsetospeed(&termios, B115200); cfsetispeed(&termios, B115200); tcsetattr(uart_fd, TCSANOW, &termios); } proc_reset(); } void proc_baudrate() { hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate)); read_event(uart_fd, buffer); usleep(200000); cfsetospeed(&termios, termios_baudrate); cfsetispeed(&termios, termios_baudrate); tcsetattr(uart_fd, TCSANOW, &termios); if (debug) { fprintf(stderr, "Done setting baudrate\n"); } } void proc_bdaddr() { hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr)); read_event(uart_fd, buffer); } void proc_enable_lpm() { hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode)); read_event(uart_fd, buffer); } void proc_scopcm() { hci_send_cmd(hci_write_sco_pcm_int, sizeof(hci_write_sco_pcm_int)); read_event(uart_fd, buffer); hci_send_cmd(hci_write_pcm_data_format, sizeof(hci_write_pcm_data_format)); read_event(uart_fd, buffer); } void proc_i2s() { hci_send_cmd(hci_write_i2spcm_interface_param, sizeof(hci_write_i2spcm_interface_param)); read_event(uart_fd, buffer); } void proc_enable_hci() { int i = N_HCI; int proto = HCI_UART_H4; if (ioctl(uart_fd, TIOCSETD, &i) < 0) { fprintf(stderr, "Can't set line discipline\n"); return; } if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) { fprintf(stderr, "Can't set hci protocol\n"); return; } fprintf(stderr, "Done setting line discpline\n"); return; } #ifdef ANDROID void read_default_bdaddr() { int sz; int fd; char path[PROPERTY_VALUE_MAX]; char bdaddr[18]; int len = 17; memset(bdaddr, 0, (len + 1) * sizeof(char)); property_get("ro.bt.bdaddr_path", path, ""); if (path[0] == 0) return; fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno), errno); return; } sz = read(fd, bdaddr, len); if (sz < 0) { fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno), errno); close(fd); return; } else if (sz != len) { fprintf(stderr, "read(%s) unexpected size %d", path, sz); close(fd); return; } if (debug) { printf("Read default bdaddr of %s\n", bdaddr); } parse_bdaddr(bdaddr); } #endif int main (int argc, char **argv) { #ifdef ANDROID read_default_bdaddr(); #endif fprintf(stderr, "###AMPAK FW Auto detection patch version = [%s]###\n", FW_TABLE_VERSION); if (parse_cmd_line(argc, argv)) { exit(1); } if (uart_fd < 0) { exit(2); } init_uart(); proc_reset(); proc_read_local_name(); proc_open_patchram(); if (use_baudrate_for_download) { if (termios_baudrate) { proc_baudrate(); } } if (hcdfile_fd > 0) { proc_patchram(); } if (termios_baudrate) { proc_baudrate(); } if (bdaddr_flag) { proc_bdaddr(); } if (enable_lpm) { proc_enable_lpm(); } if (scopcm) { proc_scopcm(); } if (i2s) { proc_i2s(); } if (enable_hci) { proc_enable_hci(); while (1) { sleep(UINT_MAX); } } exit(0); }