hciattach: download configuration at user requested baud rate

This patch support downloading configuration for Atheros AR300x HCI UART
chip at user requested baud rate instead of the initial baud rate.
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 7cb8e9e..e4d5aa1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -311,7 +311,7 @@
 
 static int ath3k_ps(int fd, struct uart_t *u, struct termios *ti)
 {
-	return ath3k_init(fd, u->bdaddr, u->speed);
+	return ath3k_init(fd, u->speed, u->init_speed, u->bdaddr, ti);
 }
 
 static int ath3k_pm(int fd, struct uart_t *u, struct termios *ti)
diff --git a/tools/hciattach.h b/tools/hciattach.h
index 2d26b77..fed0d11 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -50,6 +50,7 @@
 int texasalt_init(int fd, int speed, struct termios *ti);
 int stlc2500_init(int fd, bdaddr_t *bdaddr);
 int bgb2xx_init(int dd, bdaddr_t *bdaddr);
-int ath3k_init(int fd, char *bdaddr, int speed);
+int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
+						struct termios *ti);
 int ath3k_post(int fd, int pm);
 int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
diff --git a/tools/hciattach_ath3k.c b/tools/hciattach_ath3k.c
index 70ade30..728e660 100644
--- a/tools/hciattach_ath3k.c
+++ b/tools/hciattach_ath3k.c
@@ -922,13 +922,8 @@
 #define WRITE_BAUD_CMD_LEN   6
 #define MAX_CMD_LEN          WRITE_BDADDR_CMD_LEN
 
-/*
- * Atheros AR300x specific initialization and configuration file
- * download
- */
-int ath3k_init(int fd, char *bdaddr, int speed)
+static int set_cntrlr_baud(int fd, int speed)
 {
-	int r;
 	int baud;
 	struct timespec tm = { 0, 500000 };
 	unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
@@ -937,51 +932,6 @@
 
 	cmd[0] = HCI_COMMAND_PKT;
 
-	/* Download PS and patch */
-	r = ath_ps_download(fd);
-	if (r < 0) {
-		perror("Failed to Download configuration");
-		return -ETIMEDOUT;
-	}
-
-	/* Write BDADDR */
-	if (bdaddr) {
-		ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
-							HCI_PS_CMD_OCF));
-		ch->plen = 10;
-		ptr += HCI_COMMAND_HDR_SIZE;
-
-		ptr[0] = 0x01;
-		ptr[1] = 0x01;
-		ptr[2] = 0x00;
-		ptr[3] = 0x06;
-		str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
-
-		if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
-					WRITE_BDADDR_CMD_LEN) {
-			perror("Failed to write BD_ADDR command\n");
-			return -ETIMEDOUT;
-		}
-
-		if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
-			perror("Failed to set BD_ADDR\n");
-			return -ETIMEDOUT;
-		}
-	}
-
-	/* Send HCI Reset */
-	cmd[1] = 0x03;
-	cmd[2] = 0x0C;
-	cmd[3] = 0x00;
-
-	r = write(fd, cmd, 4);
-	if (r != 4)
-		return -ETIMEDOUT;
-
-	nanosleep(&tm, NULL);
-	if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
-		return -ETIMEDOUT;
-
 	/* set controller baud rate to user specified value */
 	ptr = cmd + 1;
 	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
@@ -1005,3 +955,95 @@
 
 	return 0;
 }
+
+/*
+ * Atheros AR300x specific initialization and configuration file
+ * download
+ */
+int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
+						struct termios *ti)
+{
+	int r;
+	int err = 0;
+	struct timespec tm = { 0, 500000 };
+	unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
+	unsigned char *ptr = cmd + 1;
+	hci_command_hdr *ch = (void *)ptr;
+
+	cmd[0] = HCI_COMMAND_PKT;
+
+	/* set both controller and host baud rate to maximum possible value */
+	err = set_cntrlr_baud(fd, speed);
+	if (err < 0)
+		return err;
+
+	err = set_speed(fd, ti, speed);
+	if (err < 0) {
+		perror("Can't set required baud rate");
+		return err;
+	}
+
+	/* Download PS and patch */
+	r = ath_ps_download(fd);
+	if (r < 0) {
+		perror("Failed to Download configuration");
+		err = -ETIMEDOUT;
+		goto failed;
+	}
+
+	/* Write BDADDR */
+	if (bdaddr) {
+		ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+							HCI_PS_CMD_OCF));
+		ch->plen = 10;
+		ptr += HCI_COMMAND_HDR_SIZE;
+
+		ptr[0] = 0x01;
+		ptr[1] = 0x01;
+		ptr[2] = 0x00;
+		ptr[3] = 0x06;
+		str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
+
+		if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
+					WRITE_BDADDR_CMD_LEN) {
+			perror("Failed to write BD_ADDR command\n");
+			err = -ETIMEDOUT;
+			goto failed;
+		}
+
+		if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+			perror("Failed to set BD_ADDR\n");
+			err = -ETIMEDOUT;
+			goto failed;
+		}
+	}
+
+	/* Send HCI Reset */
+	cmd[1] = 0x03;
+	cmd[2] = 0x0C;
+	cmd[3] = 0x00;
+
+	r = write(fd, cmd, 4);
+	if (r != 4) {
+		err = -ETIMEDOUT;
+		goto failed;
+	}
+
+	nanosleep(&tm, NULL);
+	if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+		err = -ETIMEDOUT;
+		goto failed;
+	}
+
+	err = set_cntrlr_baud(fd, speed);
+	if (err < 0)
+		return err;
+
+failed:
+	if (err < 0) {
+		set_cntrlr_baud(fd, init_speed);
+		set_speed(fd, ti, init_speed);
+	}
+
+	return err;
+}