/brcm_patchram_plus/brcm_patchram_plus.c
C | 582 lines | 407 code | 121 blank | 54 comment | 49 complexity | f3614357665325baaba74affe2b01ae2 MD5 | raw file
- /**
- * brcm_patchram_plus.c
- *
- * Copyright (C) 2009 Broadcom Corporation.
- *
- * This software is licensed under the terms of the GNU General Public License,
- * version 2, as published by the Free Software Foundation (the "GPL"), and may
- * be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
- *
- * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
- * or by writing to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
- /*****************************************************************************
- **
- ** 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>
- ** 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 <stdio.h>
- #include <getopt.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #ifdef ANDROID
- #include <termios.h>
- #else
- #include <sys/termios.h>
- #endif
- #include <string.h>
- #include <signal.h>
- #include <cutils/properties.h>
- #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 HCI_UART_H4 0
- #define HCI_UART_BCSP 1
- #define HCI_UART_3WIRE 2
- #define HCI_UART_H4DS 3
- #define HCI_UART_LL 4
- 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 debug = 0;
- struct termios termios;
- unsigned char buffer[1024];
- unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
- unsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
- unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00 };
- unsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- unsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00 };
- int
- parse_patchram(char *optarg)
- {
- 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);
- }
- return(0);
- }
- void
- BRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud)
- {
- if(baud_rate == 0 || encoded_baud == NULL) {
- fprintf(stderr, "Baudrate not supported!");
- return;
- }
- encoded_baud[3] = (unsigned char)(baud_rate >> 24);
- encoded_baud[2] = (unsigned char)(baud_rate >> 16);
- encoded_baud[1] = (unsigned char)(baud_rate >> 8);
- encoded_baud[0] = (unsigned char)(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
- parse_enable_lpm(char *optarg)
- {
- enable_lpm = 1;
- return(0);
- }
- int
- parse_enable_hci(char *optarg)
- {
- enable_hci = 1;
- return(0);
- }
- int
- parse_cmd_line(int argc, char **argv)
- {
- int c;
- int digit_optind = 0;
- typedef int (*PFI)();
- PFI parse_param[] = { parse_patchram, parse_baudrate,
- parse_bdaddr, parse_enable_lpm, parse_enable_hci };
- 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},
- {"enable_lpm", 0, 0, 0},
- {"enable_hci", 0, 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:
- printf ("option %s", long_options[option_index].name);
- if (optarg) {
- printf (" with arg %s", optarg);
- }
- printf ("\n");
- (*parse_param[option_index])(optarg);
- break;
- case 'd':
- debug = 1;
- break;
- case '?':
- //nobreak
- default:
- printf("Usage %s:\n", argv[0]);
- 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("\tuart_device_name\n");
- break;
- }
- }
- if (optind < argc) {
- if (optind < argc) {
- printf ("%s ", 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);
- }
- }
- printf ("\n");
- }
- 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(unsigned char *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, unsigned char *buffer)
- {
- int i = 0;
- int len = 3;
- int count;
- while ((count = read(fd, &buffer[i], len)) < len) {
- i += count;
- len -= count;
- }
- i += count;
- len = buffer[2];
- while ((count = read(fd, &buffer[i], len)) < len) {
- i += count;
- len -= count;
- }
- if (debug) {
- count += i;
- fprintf(stderr, "received %d\n", count);
- dump(buffer, count);
- }
- }
- void
- hci_send_cmd(unsigned char *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);
- hci_send_cmd(hci_reset, sizeof(hci_reset));
- alarm(4);
- read_event(uart_fd, buffer);
- alarm(0);
- }
- void
- proc_patchram()
- {
- int len;
- hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
- read_event(uart_fd, buffer);
- read(uart_fd, &buffer[0], 2);
- usleep(50000);
- 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);
- }
- proc_reset();
- }
- void
- proc_baudrate()
- {
- hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
- read_event(uart_fd, buffer);
- 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_enable_hci()
- {
- int i = N_HCI;
- int proto = HCI_UART_H4;
- if (enable_lpm) {
- proto = HCI_UART_LL;
- }
- 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;
- }
- void
- read_default_bdaddr()
- {
- int sz;
- int fd;
- char path[PROPERTY_VALUE_MAX];
- char bdaddr[18];
- 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, sizeof(bdaddr));
- if (sz < 0) {
- fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
- errno);
- close(fd);
- return;
- } else if (sz != sizeof(bdaddr)) {
- fprintf(stderr, "read(%s) unexpected size %d", path, sz);
- close(fd);
- return;
- }
- printf("Read default bdaddr of %s\n", bdaddr);
- parse_bdaddr(bdaddr);
- }
- int
- main (int argc, char **argv)
- {
- read_default_bdaddr();
- parse_cmd_line(argc, argv);
- if (uart_fd < 0) {
- exit(1);
- }
- init_uart();
- proc_reset();
- if (hcdfile_fd > 0) {
- proc_patchram();
- }
- if (termios_baudrate) {
- proc_baudrate();
- }
- if (bdaddr_flag) {
- proc_bdaddr();
- }
- if (enable_lpm) {
- proc_enable_lpm();
- }
- if (enable_hci) {
- proc_enable_hci();
- while (1) {
- sleep(UINT_MAX);
- }
- }
- exit(0);
- }