From 56cb70b369016fafc25ab065071eb3b869720302 Mon Sep 17 00:00:00 2001
From: Tuomas Kulve <tuomas@kulve.fi>
Date: Tue, 6 May 2008 22:03:56 +0300
Subject: [PATCH] Applied bluez-utils-hciattach-pba31308.patch.

---
 tools/hciattach.c |  286 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 282 insertions(+), 4 deletions(-)

diff --git a/tools/hciattach.c b/tools/hciattach.c
index 9a7e1b9..a44e6f7 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -134,7 +134,7 @@ static int uart_speed(int s)
 		return B4000000;
 #endif
 	default:
-		return B57600;
+		return B115200;
 	}
 }
 
@@ -151,6 +151,11 @@ static int read_hci_event(int fd, unsigned char* buf, int size)
 {
 	int remain, r;
 	int count = 0;
+	struct timeval tv = { 0, 100000 };
+	fd_set watch;
+
+	FD_ZERO(&watch);
+	FD_SET(fd,&watch);
 
 	if (size <= 0)
 		return -1;
@@ -158,9 +163,13 @@ static int read_hci_event(int fd, unsigned char* buf, int size)
 	/* The first byte identifies the packet type. For HCI event packets, it
 	 * should be 0x04, so we read until we get to the 0x04. */
 	while (1) {
+		tv.tv_sec = 1; tv.tv_usec = 100000;
+		if(select(fd+1, &watch, NULL, NULL, &tv) == 0) return -1; // timeout
 		r = read(fd, buf, 1);
 		if (r <= 0)
+		{
 			return -1;
+		}
 		if (buf[0] == 0x04)
 			break;
 	}
@@ -168,9 +177,13 @@ static int read_hci_event(int fd, unsigned char* buf, int size)
 
 	/* The next two bytes are the event code and parameter total length. */
 	while (count < 3) {
+		tv.tv_sec = 1; tv.tv_usec = 100000;
+		if(select(fd+1, &watch, NULL, NULL, &tv) == 0) return -1; // timeout
 		r = read(fd, buf + count, 3 - count);
 		if (r <= 0)
+		{
 			return -1;
+		}
 		count += r;
 	}
 
@@ -181,6 +194,8 @@ static int read_hci_event(int fd, unsigned char* buf, int size)
 		remain = size - 3;
 
 	while ((count - 3) < remain) {
+		tv.tv_sec = 1; tv.tv_usec = 100000;
+		if(select(fd+1, &watch, NULL, NULL, &tv) == 0) return -1; // timeout
 		r = read(fd, buf + count, remain - (count - 3));
 		if (r <= 0)
 			return -1;
@@ -248,12 +263,273 @@ static int ericsson(int fd, struct uart_t *u, struct termios *ti)
 /* 
  * Infineon specific initialization
  */
+
+static int infineon_manufacturer_mode(int fd, unsigned char enable)
+{
+	unsigned char cmd[10], resp[HCI_MAX_EVENT_SIZE];
+	struct timeval tv = { 1, 0 };
+	fd_set watch;
+	int retval, j;
+
+	cmd[0] = HCI_COMMAND_PKT;
+	cmd[1] = 0x11;
+	cmd[2] = 0xfc;
+	cmd[3] = 0x02;
+	cmd[4] = enable; // Enable
+	cmd[5] = 0x00; // No reset
+	if(write(fd, cmd, 6) != 6) {
+		perror("Failed to write command to enter manufacturer mode");
+		return -1;
+	}
+
+	FD_ZERO(&watch);
+	FD_SET(fd,&watch);
+	tv.tv_sec = 1; tv.tv_usec = 0;
+	retval = select(fd+1, &watch, NULL, NULL, &tv);
+
+	if(retval == -1)
+	{
+		perror("select() failed");
+		return -1;
+	} else if(retval == 0) {
+		printf("No response from BT module\n");
+		return -1;
+	} else {
+		retval = read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE);
+		if (retval < 0) {
+			perror("Error reading response");
+			return -1;
+		} else if(retval == (1+6)) {
+			if(resp[1] = 0x0e && resp[4] == cmd[1] && resp[5] == cmd[2] && resp[6] == 0x0) // Command completed OK
+			{
+				return 0;
+			} else {
+				perror("Manufacturer mode change failed");
+				for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+				return -1;
+			}
+		} else {
+			printf("Read wrong response size: %d\n", retval);
+			for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+			return -1;
+		}
+	}
+}
+
+static int pba31308(int fd, struct uart_t *u, struct termios *ti)
+{
+	unsigned char cmd[10], resp[HCI_MAX_EVENT_SIZE];
+	fd_set watch;
+	struct timeval tv = { 1, 0 };
+	struct timespec tm = {0, 50000};
+	int retval,j;
+
+	// PBA31308 implements Infineon_Set_UART_Baudrate as a manufacturer mode command
+	// So first we need to enter manufacturer mode, and then issue the command to
+	// change baud rate, then adjust out baud rate on this end, and then wait for the
+	// Infineon_Set_UART_Baudrate_Complete event
+	infineon_manufacturer_mode(fd,0x01);
+
+	cmd[0] = HCI_COMMAND_PKT;
+	cmd[1] = 0x06;
+	cmd[2] = 0xfc;
+	cmd[3] = 0x01;
+	switch(u->speed) {
+	case 9600:
+		cmd[4] = 0x00;
+		break;
+	case 19200:
+		cmd[4] = 0x01;
+		break;
+	case 38400:
+		cmd[4] = 0x02;
+		break;
+	case 57600:
+		cmd[4] = 0x03;
+		break;
+	case 115200:
+		cmd[4] = 0x04;
+		break;
+	case 230400:
+		cmd[4] = 0x05;
+		break;
+	case 460800:
+		cmd[4] = 0x06;
+		break;
+	case 921600:
+		cmd[4] = 0x07;
+		break;
+	case 1843200:
+		cmd[4] = 0x08; // not possible on gumstix
+		printf("Speed too high: setting to 115200 instead\n");
+	default:
+		cmd[4] = 0x04;
+		u->speed = 115200;
+		break;
+	}
+
+	/* Send initialization command */
+	if(write(fd, cmd, 5) != 5) {
+		perror("Failed to write init command");
+		return -1;
+	}
+
+	FD_ZERO(&watch);
+	FD_SET(fd,&watch);
+	tv.tv_sec = 1; tv.tv_usec = 0;
+	retval = select(fd+1, &watch, NULL, NULL, &tv);
+
+	if(retval == -1)
+	{
+		perror("select() failed");
+		return -1;
+	} else if(retval == 0) {
+		printf("No response from BT module\n");
+		return -1;
+	} else {
+		retval = read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE);
+		if (retval < 0) {
+			perror("Error reading response");
+			return -1;
+		} else if(retval == (1+6)) {
+			if(resp[1] == 0x0f && resp[3] == 0x00 & resp[5] == cmd[1] && resp[6] == cmd[2]) // Command status OK
+			{
+				printf("Set_UART_Baudrate accepted\n");
+			} else {
+				printf("Set_UART_Baudrate rejected\n");
+				for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+				printf("\n");
+				return -1;
+			}
+		} else {
+			printf("Read wrong response size: %d\n", retval);
+			for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+			printf("\n");
+			return -1;
+		}
+	}
+
+	if(set_speed(fd, ti, u->speed) < 0)
+	{
+		perror("Can't change baud rate");
+		return -1;
+	}
+
+	FD_ZERO(&watch);
+	FD_SET(fd,&watch);
+	tv.tv_sec = 1; tv.tv_usec = 0;
+	retval = select(fd+1, &watch, NULL, NULL, &tv);
+
+	if(retval == -1)
+	{
+		perror("select() failed");
+		return -1;
+	} else if(retval == 0) {
+		printf("No response from BT module\n");
+		return -1;
+	} else {
+		retval = read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE);
+		if (retval < 0) {
+			perror("Error reading response");
+			return -1;
+		} else if(retval == 5) {
+			if(resp[1] = 0xff && resp[3] == 0x12 && resp[4] == 0x0) // Command completed OK
+			{
+				printf("Set_UART_Baudrate completed\n");
+			} else {
+				perror("Set_UART_Baudrate failed");
+				for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+				printf("\n");
+				return -1;
+			}
+		} else {
+			printf("Read wrong response size: %d\n", retval);
+			for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+			printf("\n");
+			return -1;
+		}
+	}
+
+	infineon_manufacturer_mode(fd,0x00);
+	return 0;
+}
+
+
 static int infineon(int fd, struct uart_t *u, struct termios *ti)
 {
+	unsigned char cmd[10], resp[HCI_MAX_EVENT_SIZE];
+	fd_set watch;
+	struct timeval tv = { 1, 0 };
+	int retval,j;
+
 	if(u->speed != u->init_speed)
 	{
-		printf("Can't yet change speed for infineon module.  Will stay at %d baud\n", u->init_speed);
+		// First need to detect which kind of infineon module we're dealing with here...
+		// PBA31307 and PBA31308 both have a command OGF=0x3f,OCF=0x0005 which returns version info
+		// PBA31307 returns:				PBA31308 retunrs:
+		// Status		0x00	1 byte		Status	0x00
+		// LM-FW-Version	0x5nnn	2 bytes		HW-Platform, HW-Variant 0x37,0x03
+		// BB-FW-Version	0x05nn	2 bytes		Hw-Revision, FW-Variant 0xnn,0x03
+		// 				1 byte		FW-Revision 0xnn
+		// 				3 bytes		FW-Build	0xYMDDnn
+		// 				1 byte		FW-Patch	0xnn
+		//
+		// So the PBA31308 returns 10 bytes, PBA31307 returns only 5 bytes.  We can distinguish at byte #2 though,
+		// but need to continue reading to empty the buffer.
+
+		cmd[0] = HCI_COMMAND_PKT;
+		cmd[1] = 0x05;	// Infineon_Read_Version(PBA31308) or Infineon_Read_SW_Version(PBA31307)
+		cmd[2] = 0xfc;
+		cmd[3] = 0x00;
+
+		if(write(fd, cmd, 4) != 4) {
+			perror("Failed to write Infineon_Read(_SW)_Version command");
+			return -1;
+		}
+
+		FD_ZERO(&watch);
+		FD_SET(fd,&watch);
+		tv.tv_sec = 1; tv.tv_usec = 0;
+		retval = select(fd+1, &watch, NULL, NULL, &tv);
+
+		if(retval == -1)
+		{
+			perror("select() failed");
+			return -1;
+		} else if(retval == 0) {
+			printf("No response from BT module\n");
+			return -1;
+		} else {
+			retval = read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE);
+			if (retval < 0) {
+				printf("Error (or timeout) reading response\n");
+				return -1;
+			} else if(retval == (10+6)) { // Possiby PBA31308
+				if(resp[6] == 0x0  && resp[7] == 0x37 && resp[8] == 0x03) // PBA31308 confirmed
+				{
+					// Now we can change baudrate
+					return pba31308(fd, u, ti);
+				} else {
+					printf("Not a PBA31308\n");
+					for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+					return -1;
+				}
+			} else if(retval == (5+6)) { // Possibly PBA31307
+				if(resp[6] == 0x0 && (resp[7]&0xf0) == 0x50 && resp[10] == 0x05) // PBA31307 confirmed
+				{
+					printf("Can't yet change speed for PBA31307 module.  Will stay at %d baud\n", u->init_speed);
 		u->speed = u->init_speed;
+				} else {
+					printf("Not a PBA31307\n");
+					for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+					return -1;
+				}
+			} else {
+				printf("Read wrong response size: %d\n", retval);
+				for(j=0; j<retval; j++) printf("0x%02x ",resp[j]);
+				return -1;
+			}
+		}
 	}
 	return 0;
 }
@@ -812,7 +1088,8 @@ void gumstix_reset(int fd)
 	struct timespec tm = { 0, 500000000 };
 	struct timeval tv = { 1, 0 };
 	fd_set watch;
-	int retval;
+	int retval, j;
+	unsigned char resp[HCI_MAX_EVENT_SIZE];
 
 	tcflush(fd, TCIOFLUSH);
 	system("echo clear > /proc/gpio/GPIO12");
@@ -837,8 +1114,9 @@ static int gumstix(int fd, struct uart_t *u, struct termios *ti)
 {
 	fd_set watch;
 	struct timeval tv = { 1, 0 };
+
 	unsigned char cmd[10], resp[HCI_MAX_EVENT_SIZE];
-	int baudrates[] = { 57600, 115200, 921600 };
+	int baudrates[] = { u->init_speed, 921600, 115200, 57600 };
 	int old_alarm = alarm(20); // Extend timeout
 	int i, j, retval, tries;
 
-- 
1.5.4.5

