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
42 static int debug = 0;
43
do_command(int fd,uint8_t ogf,uint16_t ocf,uint8_t * cparam,int clen,uint8_t * rparam,int rlen)44 static 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
load_file(int dd,uint16_t version,const char * suffix)119 static 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
stlc2500_init(int dd,bdaddr_t * bdaddr)198 int 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
bgb2xx_init(int dd,bdaddr_t * bdaddr)253 int 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