2009-05-19 21:49:12 +00:00
|
|
|
/*
|
|
|
|
* bt_control_iphone.c
|
|
|
|
*
|
|
|
|
* control Bluetooth module using BlueTool
|
|
|
|
*
|
|
|
|
* Created by Matthias Ringwald on 5/19/09.
|
|
|
|
*/
|
|
|
|
|
2009-07-12 15:33:07 +00:00
|
|
|
#include "../config.h"
|
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
#include "bt_control_iphone.h"
|
2009-05-26 20:20:31 +00:00
|
|
|
#include "hci_transport.h"
|
2009-06-09 20:39:03 +00:00
|
|
|
#include "hci.h"
|
2009-05-26 20:20:31 +00:00
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
#include <sys/utsname.h> // uname
|
|
|
|
#include <stdlib.h> // system
|
|
|
|
#include <stdio.h> // sscanf, printf
|
|
|
|
#include <fcntl.h> // open
|
|
|
|
#include <string.h> // strcpy, strcat, strncmp
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <unistd.h>
|
2009-05-20 20:46:35 +00:00
|
|
|
#include <errno.h>
|
2009-05-19 21:49:12 +00:00
|
|
|
|
2009-07-01 20:49:57 +00:00
|
|
|
// minimal IOKit
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <Availability.h>
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_2_0
|
|
|
|
#include <mach/mach.h>
|
|
|
|
#define IOKIT
|
|
|
|
#include <device/device_types.h>
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
kern_return_t IOMasterPort( mach_port_t bootstrapPort, mach_port_t * masterPort );
|
|
|
|
CFMutableDictionaryRef IOServiceNameMatching(const char * name );
|
|
|
|
CFTypeRef IORegistryEntrySearchCFProperty(mach_port_t entry, const io_name_t plane,
|
|
|
|
CFStringRef key, CFAllocatorRef allocator, UInt32 options );
|
|
|
|
mach_port_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching );
|
|
|
|
kern_return_t IOObjectRelease(mach_port_t object);
|
|
|
|
#endif
|
|
|
|
#endif
|
2009-06-14 20:56:41 +00:00
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
#define BUFF_LEN 80
|
|
|
|
static char buffer[BUFF_LEN+1];
|
|
|
|
|
2009-07-01 20:49:57 +00:00
|
|
|
// bd addr from iphone/ipod IORegistry
|
|
|
|
// the Broadcom chipsets done store a BD_ADDR and the one on the iPhone
|
|
|
|
// is different to the one reported by About in the Settings app
|
2009-06-14 20:56:41 +00:00
|
|
|
static bd_addr_t ioRegAddr;
|
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
/**
|
|
|
|
* get machine name
|
|
|
|
*/
|
|
|
|
static struct utsname unmae_info;
|
|
|
|
static char *get_machine_name(void){
|
|
|
|
uname(&unmae_info);
|
|
|
|
return unmae_info.machine;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* on iPhone/iPod touch
|
|
|
|
*/
|
|
|
|
static int iphone_valid(void *config){
|
|
|
|
char * machine = get_machine_name();
|
2009-06-09 20:39:03 +00:00
|
|
|
if (!strncmp("iPhone", machine, strlen("iPhone" ))) return 1;
|
|
|
|
if (!strncmp("iPod2,1", machine, strlen("iPod2,1"))) return 1;
|
2009-08-11 22:27:23 +00:00
|
|
|
if (!strncmp("iPod3,1", machine, strlen("iPod2,1"))) return 1;
|
2009-06-09 20:39:03 +00:00
|
|
|
return 0;
|
2009-05-19 21:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char * iphone_name(void *config){
|
|
|
|
return get_machine_name();
|
|
|
|
}
|
|
|
|
|
2009-06-14 20:38:50 +00:00
|
|
|
// Get BD_ADDR from IORegistry
|
|
|
|
static void ioregistry_get_bd_addr() {
|
2009-07-01 20:49:57 +00:00
|
|
|
#ifdef IOKIT
|
2009-06-14 20:38:50 +00:00
|
|
|
mach_port_t mp;
|
|
|
|
IOMasterPort(MACH_PORT_NULL,&mp);
|
|
|
|
CFMutableDictionaryRef bt_matching = IOServiceNameMatching("bluetooth");
|
|
|
|
mach_port_t bt_service = IOServiceGetMatchingService(mp, bt_matching);
|
|
|
|
CFTypeRef bt_typeref = IORegistryEntrySearchCFProperty(bt_service,"IODevicTree",CFSTR("local-mac-address"), kCFAllocatorDefault, 1);
|
|
|
|
CFDataGetBytes(bt_typeref,CFRangeMake(0,CFDataGetLength(bt_typeref)),ioRegAddr); // buffer needs to be unsigned char
|
|
|
|
IOObjectRelease(bt_service);
|
2009-07-01 20:49:57 +00:00
|
|
|
#else
|
|
|
|
// use dummy addr if not on iphone/ipod touch
|
|
|
|
int i = 0;
|
|
|
|
for (i=0;i<6;i++) {
|
|
|
|
ioRegAddr[i] = i;
|
|
|
|
}
|
2009-06-14 20:38:50 +00:00
|
|
|
#endif
|
2009-07-01 20:49:57 +00:00
|
|
|
}
|
2009-06-14 20:38:50 +00:00
|
|
|
|
2009-05-26 20:20:31 +00:00
|
|
|
static void iphone_set_pskey(int fd, int key, int value){
|
|
|
|
sprintf(buffer, "csr -p 0x%04x=0x%04x\n", key, value);
|
|
|
|
write(fd, buffer, 21);
|
|
|
|
}
|
2009-05-25 20:37:12 +00:00
|
|
|
|
|
|
|
static int iphone_write_initscript (void *config, int output){
|
2009-05-26 20:20:31 +00:00
|
|
|
|
|
|
|
// get uart config
|
|
|
|
hci_uart_config_t * uart_config = (hci_uart_config_t *) config;
|
|
|
|
|
|
|
|
// calculate baud rate (assume rate is multiply of 100)
|
|
|
|
uint32_t baud_key = (4096 * (uart_config->baudrate/100) + 4999) / 10000;
|
2009-06-14 20:38:50 +00:00
|
|
|
// printf("Baud key %u\n", baud_key);
|
2009-05-26 20:20:31 +00:00
|
|
|
|
2009-05-25 20:37:12 +00:00
|
|
|
// construct script path from device name
|
2009-05-20 20:46:35 +00:00
|
|
|
strcpy(buffer, "/etc/bluetool/");
|
2009-05-19 21:49:12 +00:00
|
|
|
char *machine = get_machine_name();
|
|
|
|
strcat(buffer, machine);
|
2009-08-11 22:27:23 +00:00
|
|
|
if (strncmp(machine, "iPhone1,", strlen("iPhone1,")) == 0) {
|
|
|
|
// It's an iPhone 2G or 3G
|
2009-06-09 20:39:03 +00:00
|
|
|
strcat(buffer, ".init.script");
|
|
|
|
} else {
|
2009-08-11 22:27:23 +00:00
|
|
|
// It's an iPod Touch (2G) or an iPhone 3GS
|
2009-06-09 20:39:03 +00:00
|
|
|
strcat(buffer, ".boot.script");
|
|
|
|
}
|
2009-05-19 21:49:12 +00:00
|
|
|
|
2009-07-01 20:49:57 +00:00
|
|
|
// get bd_addr from IORegistry
|
|
|
|
ioregistry_get_bd_addr();
|
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
// open script
|
|
|
|
int input = open(buffer, O_RDONLY);
|
2009-05-20 20:46:35 +00:00
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
int pos = 0;
|
|
|
|
int mirror = 0;
|
|
|
|
int store = 1;
|
|
|
|
while (1){
|
|
|
|
int chars = read(input, &buffer[pos], 1);
|
2009-05-25 20:37:12 +00:00
|
|
|
|
2009-05-19 21:49:12 +00:00
|
|
|
// end-of-line
|
|
|
|
if (chars == 0 || buffer[pos]=='\n' || buffer[pos]== '\r'){
|
|
|
|
if (store) {
|
|
|
|
// stored characters
|
2009-05-20 20:46:35 +00:00
|
|
|
write(output, buffer, pos+chars);
|
2009-05-19 21:49:12 +00:00
|
|
|
}
|
|
|
|
if (mirror) {
|
2009-05-20 20:46:35 +00:00
|
|
|
write(output, "\n", 1);
|
2009-05-19 21:49:12 +00:00
|
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
mirror = 0;
|
|
|
|
store = 1;
|
|
|
|
if (chars) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mirror
|
|
|
|
if (mirror){
|
2009-05-20 20:46:35 +00:00
|
|
|
write(output, &buffer[pos], 1);
|
2009-05-19 21:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// store
|
|
|
|
if (store) {
|
|
|
|
pos++;
|
|
|
|
}
|
2009-07-01 20:49:57 +00:00
|
|
|
|
|
|
|
// iPhone - set BD_ADDR after "csr -i"
|
|
|
|
if (store == 1 && pos == 6 && strncmp(buffer, "csr -i", 6) == 0) {
|
|
|
|
store = 0;
|
|
|
|
write(output, buffer, pos); // "csr -i"
|
|
|
|
sprintf(buffer,"\ncsr -p 0x0001=0x00%.2x,0x%.2x%.2x,0x00%.2x,0x%.2x%.2x\n",
|
|
|
|
ioRegAddr[3], ioRegAddr[4], ioRegAddr[5], ioRegAddr[2], ioRegAddr[0], ioRegAddr[1]);
|
|
|
|
write(output, buffer, 42);
|
|
|
|
}
|
|
|
|
|
2009-06-09 20:39:03 +00:00
|
|
|
// iPod2,1
|
2009-06-09 21:04:12 +00:00
|
|
|
// check for "bcm -X" cmds
|
2009-07-01 20:49:57 +00:00
|
|
|
if (store == 1 && pos == 6){
|
|
|
|
if (strncmp(buffer, "bcm -", 5) == 0) {
|
2009-06-09 21:04:12 +00:00
|
|
|
store = 0;
|
2009-06-09 20:39:03 +00:00
|
|
|
switch (buffer[5]){
|
|
|
|
case 'a': // BT Address
|
2009-07-01 20:49:57 +00:00
|
|
|
write(output, buffer, pos); // "bcm -a"
|
|
|
|
sprintf(buffer, " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", ioRegAddr[0], ioRegAddr[1],
|
2009-06-14 20:38:50 +00:00
|
|
|
ioRegAddr[2], ioRegAddr[3], ioRegAddr[4], ioRegAddr[5]);
|
|
|
|
write(output, buffer, 18);
|
2009-06-09 20:39:03 +00:00
|
|
|
mirror = 0;
|
|
|
|
break;
|
2009-07-01 20:49:57 +00:00
|
|
|
case 'b': // baud rate command OS 2.x
|
|
|
|
case 'B': // baud rate command OS 3.x
|
|
|
|
buffer[5] = 'b';
|
|
|
|
write(output, buffer, pos); // "bcm -b"
|
|
|
|
sprintf(buffer, " %u\n", uart_config->baudrate);
|
2009-06-09 20:39:03 +00:00
|
|
|
write(output, buffer, strlen(buffer));
|
|
|
|
mirror = 0;
|
|
|
|
break;
|
|
|
|
case 's': // sleep mode - replace with "wake" command?
|
|
|
|
write(output,"wake on\n", strlen("wake on\n"));
|
|
|
|
mirror = 0;
|
|
|
|
break;
|
2009-06-09 21:04:12 +00:00
|
|
|
default: // other "bcm -X" command
|
2009-06-09 20:39:03 +00:00
|
|
|
write(output, buffer, pos);
|
|
|
|
mirror = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-01 20:49:57 +00:00
|
|
|
|
|
|
|
// iPhone1,1 & iPhone 2,1: OS 3.x
|
|
|
|
// check for "csr -B" and "csr -T"
|
|
|
|
if (store == 1 && pos == 6){
|
|
|
|
if (strncmp(buffer, "csr -", 5) == 0) {
|
|
|
|
switch(buffer[5]){
|
|
|
|
case 'T': // Transport Mode
|
|
|
|
store = 0;
|
|
|
|
break;
|
|
|
|
case 'B': // Baud rate
|
|
|
|
iphone_set_pskey(output, 0x01be, baud_key);
|
|
|
|
store = 0;
|
|
|
|
break;
|
|
|
|
default: // wait for full command
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// iPhone1,1 & iPhone 2,1: OS 2.x
|
2009-06-09 21:04:12 +00:00
|
|
|
// check for "csr -p 0x1234=0x5678" (20)
|
|
|
|
if (store == 1 && pos == 20) {
|
|
|
|
int pskey, value;
|
|
|
|
store = 0;
|
|
|
|
if (sscanf(buffer, "csr -p 0x%x=0x%x", &pskey, &value) == 2){
|
|
|
|
switch (pskey) {
|
|
|
|
case 0x01f9: // UART MODE
|
|
|
|
case 0x01c1: // Configure H5 mode
|
|
|
|
mirror = 0;
|
|
|
|
break;
|
|
|
|
case 0x01be: // PSKET_UART_BAUD_RATE
|
|
|
|
iphone_set_pskey(output, 0x01be, baud_key);
|
|
|
|
mirror = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// anything else: dump buffer and start forwarding
|
|
|
|
write(output, buffer, pos);
|
|
|
|
mirror = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
write(output, buffer, pos);
|
|
|
|
mirror = 1;
|
|
|
|
}
|
|
|
|
}
|
2009-05-19 21:49:12 +00:00
|
|
|
}
|
2009-05-25 20:37:12 +00:00
|
|
|
// close input
|
2009-05-20 21:25:20 +00:00
|
|
|
close(input);
|
2009-05-25 20:37:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2009-05-20 21:25:20 +00:00
|
|
|
|
2009-05-25 20:37:12 +00:00
|
|
|
static int iphone_on (void *config){
|
|
|
|
#if 0
|
2009-07-01 20:49:57 +00:00
|
|
|
// use tmp file for testing
|
2009-05-25 20:37:12 +00:00
|
|
|
int output = open("/tmp/bt.init", O_WRONLY | O_CREAT | O_TRUNC);
|
|
|
|
iphone_write_initscript(config, output);
|
|
|
|
close(output);
|
|
|
|
system ("BlueTool < /tmp/bt.init");
|
|
|
|
#else
|
|
|
|
// modify original script on the fly
|
|
|
|
FILE * outputFile = popen("BlueTool", "r+");
|
|
|
|
setvbuf(outputFile, NULL, _IONBF, 0);
|
|
|
|
int output = fileno(outputFile);
|
|
|
|
iphone_write_initscript(config, output);
|
2009-05-20 21:25:20 +00:00
|
|
|
|
2009-05-25 20:37:12 +00:00
|
|
|
// log output
|
2009-05-20 21:25:20 +00:00
|
|
|
fflush(outputFile);
|
2009-05-25 20:37:12 +00:00
|
|
|
int singlechar;
|
|
|
|
while (1) {
|
|
|
|
singlechar = fgetc(outputFile);
|
|
|
|
if (singlechar == EOF) break;
|
|
|
|
printf("%c", singlechar);
|
|
|
|
};
|
2009-05-20 21:25:20 +00:00
|
|
|
pclose(outputFile);
|
2009-05-25 20:37:12 +00:00
|
|
|
|
|
|
|
#endif
|
2009-07-01 20:49:57 +00:00
|
|
|
// if we sleep for about 3 seconds, we miss a strage packet... but we don't care
|
2009-05-25 20:37:12 +00:00
|
|
|
// sleep(3);
|
2009-05-19 21:49:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int iphone_off (void *config){
|
|
|
|
// power off
|
|
|
|
system ("echo \"power off\n quit\" | BlueTool");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// single instance
|
|
|
|
bt_control_t bt_control_iphone = {
|
|
|
|
iphone_on,
|
|
|
|
iphone_off,
|
|
|
|
iphone_valid,
|
|
|
|
iphone_name
|
|
|
|
};
|