1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <stdio.h> 29#include <errno.h> 30#include <fcntl.h> 31#include <unistd.h> 32#include <stdlib.h> 33#include <stdint.h> 34#include <string.h> 35#include <dirent.h> 36#include <sys/param.h> 37 38#include <bluetooth/bluetooth.h> 39 40#include "hciattach.h" 41 42static int debug = 0; 43 44static int do_command(int fd, uint8_t ogf, uint16_t ocf, 45 uint8_t *cparam, int clen, uint8_t *rparam, int rlen) 46{ 47 //uint16_t opcode = (uint16_t) ((ocf & 0x03ff) | (ogf << 10)); 48 unsigned char cp[260], rp[260]; 49 int len, size, offset = 3; 50 51 cp[0] = 0x01; 52 cp[1] = ocf & 0xff; 53 cp[2] = ogf << 2 | ocf >> 8; 54 cp[3] = clen; 55 56 if (clen > 0) 57 memcpy(cp + 4, cparam, clen); 58 59 if (debug) { 60 int i; 61 printf("[<"); 62 for (i = 0; i < clen + 4; i++) 63 printf(" %02x", cp[i]); 64 printf("]\n"); 65 } 66 67 if (write(fd, cp, clen + 4) < 0) 68 return -1; 69 70 do { 71 if (read(fd, rp, 1) < 1) 72 return -1; 73 } while (rp[0] != 0x04); 74 75 if (read(fd, rp + 1, 2) < 2) 76 return -1; 77 78 do { 79 len = read(fd, rp + offset, sizeof(rp) - offset); 80 offset += len; 81 } while (offset < rp[2] + 3); 82 83 if (debug) { 84 int i; 85 printf("[>"); 86 for (i = 0; i < offset; i++) 87 printf(" %02x", rp[i]); 88 printf("]\n"); 89 } 90 91 if (rp[0] != 0x04) { 92 errno = EIO; 93 return -1; 94 } 95 96 switch (rp[1]) { 97 case 0x0e: /* command complete */ 98 if (rp[6] != 0x00) 99 return -ENXIO; 100 offset = 3 + 4; 101 size = rp[2] - 4; 102 break; 103 case 0x0f: /* command status */ 104 /* fall through */ 105 default: 106 offset = 3; 107 size = rp[2]; 108 break; 109 } 110 111 if (!rparam || rlen < size) 112 return -ENXIO; 113 114 memcpy(rparam, rp + offset, size); 115 116 return size; 117} 118 119static int load_file(int dd, uint16_t version, const char *suffix) 120{ 121 DIR *dir; 122 struct dirent *d; 123 char pathname[PATH_MAX], filename[NAME_MAX], prefix[20]; 124 unsigned char cmd[256]; 125 unsigned char buf[256]; 126 uint8_t seqnum = 0; 127 int fd, size, len, found_fw_file; 128 129 memset(filename, 0, sizeof(filename)); 130 131 snprintf(prefix, sizeof(prefix), "STLC2500_R%d_%02d_", 132 version >> 8, version & 0xff); 133 134 strcpy(pathname, "/lib/firmware"); 135 dir = opendir(pathname); 136 if (!dir) { 137 strcpy(pathname, "."); 138 dir = opendir(pathname); 139 if (!dir) 140 return -errno; 141 } 142 143 found_fw_file = 0; 144 while (1) { 145 d = readdir(dir); 146 if (!d) 147 break; 148 149 if (strncmp(d->d_name + strlen(d->d_name) - strlen(suffix), 150 suffix, strlen(suffix))) 151 continue; 152 153 if (strncmp(d->d_name, prefix, strlen(prefix))) 154 continue; 155 156 snprintf(filename, sizeof(filename), "%s/%s", 157 pathname, d->d_name); 158 found_fw_file = 1; 159 } 160 161 closedir(dir); 162 163 if (!found_fw_file) 164 return -ENOENT; 165 166 printf("Loading file %s\n", filename); 167 168 fd = open(filename, O_RDONLY); 169 if (fd < 0) { 170 perror("Can't open firmware file"); 171 return -errno; 172 } 173 174 while (1) { 175 size = read(fd, cmd + 1, 254); 176 if (size <= 0) 177 break; 178 179 cmd[0] = seqnum; 180 181 len = do_command(dd, 0xff, 0x002e, cmd, size + 1, buf, sizeof(buf)); 182 if (len < 1) 183 break; 184 185 if (buf[0] != seqnum) { 186 fprintf(stderr, "Sequence number mismatch\n"); 187 break; 188 } 189 190 seqnum++; 191 } 192 193 close(fd); 194 195 return 0; 196} 197 198int stlc2500_init(int dd, bdaddr_t *bdaddr) 199{ 200 unsigned char cmd[16]; 201 unsigned char buf[254]; 202 uint16_t version; 203 int len; 204 int err; 205 206 /* Hci_Cmd_Ericsson_Read_Revision_Information */ 207 len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); 208 if (len < 0) 209 return -1; 210 211 printf("%s\n", buf); 212 213 /* HCI_Read_Local_Version_Information */ 214 len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf)); 215 if (len < 0) 216 return -1; 217 218 version = buf[2] << 8 | buf[1]; 219 220 err = load_file(dd, version, ".ptc"); 221 if (err < 0) { 222 if (err == -ENOENT) 223 fprintf(stderr, "No ROM patch file loaded.\n"); 224 else 225 return -1; 226 } 227 228 err = load_file(dd, buf[2] << 8 | buf[1], ".ssf"); 229 if (err < 0) { 230 if (err == -ENOENT) 231 fprintf(stderr, "No static settings file loaded.\n"); 232 else 233 return -1; 234 } 235 236 cmd[0] = 0xfe; 237 cmd[1] = 0x06; 238 bacpy((bdaddr_t *) (cmd + 2), bdaddr); 239 240 /* Hci_Cmd_ST_Store_In_NVDS */ 241 len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); 242 if (len < 0) 243 return -1; 244 245 /* HCI_Reset : applies parameters*/ 246 len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); 247 if (len < 0) 248 return -1; 249 250 return 0; 251} 252 253int bgb2xx_init(int dd, bdaddr_t *bdaddr) 254{ 255 unsigned char cmd[16]; 256 unsigned char buf[254]; 257 int len; 258 259 len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); 260 if (len < 0) 261 return -1; 262 263 printf("%s\n", buf); 264 265 cmd[0] = 0xfe; 266 cmd[1] = 0x06; 267 bacpy((bdaddr_t *) (cmd + 2), bdaddr); 268 269 len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); 270 if (len < 0) 271 return -1; 272 273 len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); 274 if (len < 0) 275 return -1; 276 277 return 0; 278} 279