• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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