loader.c
Go to the documentation of this file.
1 /*
2  * This file is part of the OpenKinect Project. http://www.openkinect.org
3  *
4  * Copyright (c) 2011 individual OpenKinect contributors. See the CONTRIB file
5  * for details.
6  *
7  * This code is licensed to you under the terms of the Apache License, version
8  * 2.0, or, at your option, the terms of the GNU General Public License,
9  * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
10  * or the following URLs:
11  * http://www.apache.org/licenses/LICENSE-2.0
12  * http://www.gnu.org/licenses/gpl-2.0.txt
13  *
14  * If you redistribute this file in source form, modified or unmodified, you
15  * may:
16  * 1) Leave this header intact and distribute it under the same terms,
17  * accompanying it with the APACHE20 and GPL20 files, or
18  * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
19  * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file
20  * In all cases you must keep the copyright notice intact and include a copy
21  * of the CONTRIB file.
22  *
23  * Binary distributions must follow the binary distribution requirements of
24  * either License.
25  */
26 
27 #include "libfreenect.h"
28 #include "freenect_internal.h"
29 #include "loader.h"
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 
35 
37  int i;
38  for(i = 0; i < 24; i++)
39  FN_INFO("%02X ", ((unsigned char*)(&cmd))[i]);
40  FN_INFO("\n");
41 }
42 
44  int i;
45  for(i = 0; i < 24; i++)
46  FN_INFO("%02X ", ((unsigned char*)(&cmd))[i]);
47  FN_INFO("(%d more zeros)\n", (int)(sizeof(cmd)-24));
48 }
49 
50 static int get_reply(fnusb_dev* dev) {
52  unsigned char dump[512];
54  int res;
55  int transferred;
56  res = fnusb_bulk(dev, 0x81, dump, 512, &transferred);
57  if(res != 0 || transferred != sizeof(bootloader_status_code)) {
58  FN_ERROR("Error reading reply: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)(sizeof(bootloader_status_code)));
59  return res;
60  }
61  memcpy(&buffer, dump, sizeof(bootloader_status_code));
62  if(fn_le32(buffer.magic) != 0x0a6fe000) {
63  FN_ERROR("Error reading reply: invalid magic %08X\n",buffer.magic);
64  return -1;
65  }
66  if(fn_le32(buffer.tag) != dev->parent->audio_tag) {
67  FN_ERROR("Error reading reply: non-matching tag number %08X (expected %08X)\n", buffer.tag, dev->parent->audio_tag);
68  return -1;
69  }
70  if(fn_le32(buffer.status) != 0) {
71  FN_ERROR("Notice reading reply: last uint32_t was nonzero: %d\n", buffer.status);
72  }
73  FN_INFO("Reading reply: ");
74  int i;
75  for(i = 0; i < transferred; ++i) {
76  FN_INFO("%02X ", ((unsigned char*)(&buffer))[i]);
77  }
78  FN_INFO("\n");
79  return res;
80 }
81 
82 static int check_version_string(fnusb_dev* dev) {
84  bootloader_command bootcmd;
85  memset(&bootcmd, 0, sizeof(bootcmd));
86  bootcmd.magic = fn_le32(0x06022009);
87  bootcmd.tag = fn_le32(dev->parent->audio_tag);
88  bootcmd.bytes = fn_le32(0x60);
89  bootcmd.cmd = fn_le32(0);
90  bootcmd.addr = fn_le32(0x15);
91  unsigned char buffer[512];
92  int res;
93  int transferred;
94 
95  FN_INFO("check_version_string(): About to send: ");
96  dump_bl_cmd(ctx, bootcmd);
97 
98  // Send "get version string" command
99  res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred);
100  if(res != 0 || transferred != sizeof(bootcmd)) {
101  FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)sizeof(bootcmd));
102  return -1;
103  }
104 
105  // Read version string reply
106  res = fnusb_bulk(dev, 0x81, buffer, 512, &transferred);
107  if(res != 0 ) {
108  FN_ERROR("Error reading version string: %d\ttransferred: %d (expected %d)\n", res, transferred, 0x60);
109  return res;
110  }
111  FN_INFO("Read version string: ");
112  int i;
113  for(i = 0; i < transferred; ++i) {
114  FN_INFO("%02X ", buffer[i]);
115  }
116  FN_INFO("\n");
117 
118  // Read status code reply
119  res = get_reply(dev);
120  dev->parent->audio_tag++;
121  return res;
122 }
123 
124 
125 FN_INTERNAL int upload_firmware(fnusb_dev* dev, char * filename) {
127  /* Search for firmware file (audios.bin) in the following places:
128  * $LIBFREENECT_FIRMWARE_PATH
129  * .
130  * ${HOME}/.libfreenect
131  * /usr/local/share/libfreenect
132  * /usr/share/libfreenect
133  * ./../Resources/ ( for OS X )
134  */
135 
136  //need to add a forward slash
137  char fw_filename[1024];
138  sprintf(fw_filename, "/%s", filename);
139 
140  int filenamelen = strlen(fw_filename);
141  int i;
142  int searchpathcount;
143  FILE* fw = NULL;
144 
145  for(i = 0, searchpathcount = 6; !fw && i < searchpathcount; i++) {
146  char* fwfile;
147  int needs_free = 0;
148  switch(i) {
149  case 0: {
150  char* envpath = getenv("LIBFREENECT_FIRMWARE_PATH");
151  if (!envpath)
152  continue;
153  int pathlen = strlen(envpath);
154  fwfile = (char *)malloc(pathlen + filenamelen + 1);
155  strcpy(fwfile, envpath);
156  strcat(fwfile, fw_filename);
157  needs_free = 1;
158  }
159  break;
160  case 1:
161  //fwfile = "./audios.bin";
162  fwfile = (char *)malloc(2048);
163  needs_free = 1;
164  sprintf(fwfile, ".%s", fw_filename);
165  break;
166  case 2: {
167  // Construct $HOME/.libfreenect/
168  char* home = getenv("HOME");
169  if (!home)
170  continue;
171  int homelen = strlen(home);
172  char* dotfolder = "/.libfreenect";
173  int locallen = strlen(dotfolder);
174  fwfile = (char*)malloc(homelen + locallen + filenamelen + 1);
175  strcpy(fwfile, home);
176  strcat(fwfile, dotfolder);
177  strcat(fwfile, fw_filename);
178  needs_free = 1;
179  }
180  break;
181  case 3:
182  //fwfile = "/usr/local/share/libfreenect/audios.bin";
183  sprintf(fwfile, "/usr/local/share/libfreenect%s", fw_filename);
184 
185  break;
186  case 4:
187  //fwfile = "/usr/share/libfreenect/audios.bin";
188  fwfile = (char *)malloc(2048);
189  needs_free = 1;
190  sprintf(fwfile, "/usr/share/libfreenect%s", fw_filename);
191  break;
192  case 5:
193  //fwfile = "./../Resources/audios.bin"; //default for OS X equivilant to: "./audios.bin";
194  fwfile = (char *)malloc(2048);
195  needs_free = 1;
196  sprintf(fwfile, "./../Resources%s", fw_filename);
197  break;
198  default: break;
199  }
200  FN_INFO("Trying to open %s as firmware...\n", fwfile);
201  fw = fopen(fwfile, "rb");
202  if (needs_free) {
203  free(fwfile);
204  }
205  }
206  if (!fw) {
207  FN_ERROR("upload_firmware: failed to find firmware file.\n");
208  return -errno;
209  }
210 
211  // get the number of bytes of the file
212  fseek(fw , 0, SEEK_END);
213  int fw_num_bytes = ftell(fw);
214  rewind(fw);
215 
216  if( fw_num_bytes <= 0 ){
217  FN_ERROR("upload_firmware: failed to find file with any data.\n");
218  return -errno;
219  }
220 
221  unsigned char * fw_bytes = (unsigned char *)malloc(fw_num_bytes);
222  int numRead = fread(fw_bytes, 1, fw_num_bytes, fw);
223  fw_num_bytes = numRead; // just in case
224 
225  int retVal = upload_firmware_from_memory(dev, fw_bytes, fw_num_bytes);
226 
227  fclose(fw);
228  fw = NULL;
229 
230  return retVal;
231 }
232 
233 FN_INTERNAL int upload_firmware_from_memory(fnusb_dev* dev, unsigned char * fw_from_mem, unsigned int fw_size_in_btyes) {
235  bootloader_command bootcmd;
236  memset(&bootcmd, 0, sizeof(bootcmd));
237  bootcmd.magic = fn_le32(0x06022009);
238 
239  int res;
240  int transferred;
241 
242  firmware_header fwheader;
243  int read = 0;
244  int bytesLeft = fw_size_in_btyes;
245  unsigned char * readPtr = &fw_from_mem[0];
246 
247  if (fw_size_in_btyes < sizeof(firmware_header)) {
248  FN_ERROR("upload_firmware: firmware image too small, has no header?\n");
249  return -errno;
250  }
251 
252  memcpy(&fwheader, readPtr, sizeof(firmware_header));
253 
254  // The file is serialized as little endian.
255  fwheader.magic = fn_le32(fwheader.magic);
256  fwheader.ver_major = fn_le16(fwheader.ver_major);
257  fwheader.ver_minor = fn_le16(fwheader.ver_minor);
258  fwheader.ver_release = fn_le16(fwheader.ver_release);
259  fwheader.ver_patch = fn_le16(fwheader.ver_patch);
260  fwheader.base_addr = fn_le32(fwheader.base_addr);
261  fwheader.size = fn_le32(fwheader.size);
262  fwheader.entry_addr = fn_le32(fwheader.entry_addr);
263  FN_INFO("Found firmware image:\n");
264  FN_INFO("\tmagic %08X\n", fwheader.magic);
265  FN_INFO("\tversion %02d.%02d.%02d.%02d\n", fwheader.ver_major, fwheader.ver_minor, fwheader.ver_release, fwheader.ver_patch);
266  FN_INFO("\tbase address 0x%08x\n", fwheader.base_addr);
267  FN_INFO("\tsize 0x%08x\n", fwheader.size);
268  FN_INFO("\tentry point 0x%08x\n", fwheader.entry_addr);
269 
270 
271  uint32_t addr = fwheader.base_addr;
272  unsigned char page[0x4000];
273  int readIndex = 0;
274  int total_bytes_sent = 0;
275  do {
276 
277  read = (0x4000 > fwheader.size - total_bytes_sent) ? fwheader.size - total_bytes_sent : 0x4000;
278 
279  // sanity check
280  if( read > bytesLeft ){
281  read = bytesLeft;
282  }
283  if (read <= 0) {
284  break;
285  }
286 
287  memcpy(page, &readPtr[readIndex], read);
288  readIndex += read;
289  bytesLeft -= read;
290 
291  bootcmd.tag = fn_le32(dev->parent->audio_tag);
292  bootcmd.bytes = fn_le32(read);
293  bootcmd.cmd = fn_le32(0x03);
294  bootcmd.addr = fn_le32(addr);
295  FN_INFO("About to send: ");
296  dump_bl_cmd(ctx, bootcmd);
297  // Send it off!
298  res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred);
299  if(res != 0 || transferred != sizeof(bootcmd)) {
300  FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)(sizeof(bootcmd)));
301  return -1;
302  }
303  int bytes_sent = 0;
304  while(bytes_sent < read) {
305  int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent);
306  res = fnusb_bulk(dev, 1, &page[bytes_sent], to_send, &transferred);
307  if(res != 0 || transferred != to_send) {
308  FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send);
309  return -1;
310  }
311  bytes_sent += to_send;
312  total_bytes_sent += to_send;
313  }
314  res = get_reply(dev);
315  addr += (uint32_t)read;
316  dev->parent->audio_tag++;
317  } while (read > 0);
318 
319  if (total_bytes_sent != fwheader.size) {
320  FN_ERROR("upload_firmware: firmware image declared %d bytes, but file only contained %d bytes\n", fwheader.size, total_bytes_sent);
321  return -1;
322  }
323 
324  bootcmd.tag = fn_le32(dev->parent->audio_tag);
325  bootcmd.bytes = fn_le32(0);
326  bootcmd.cmd = fn_le32(0x04);
327  bootcmd.addr = fn_le32(fwheader.entry_addr);
328  dump_bl_cmd(ctx, bootcmd);
329  res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred);
330  if(res != 0 || transferred != sizeof(bootcmd)) {
331  FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(bootcmd));
332  return -1;
333  }
334  res = get_reply(dev);
335  dev->parent->audio_tag++;
336  FN_INFO("Firmware successfully uploaded and launched. Device will disconnect and reenumerate.\n");
337  return 0;
338 }
339 
341  // Now we upload the CEMD data.
343  cemdloader_command cemdcmd;
344  memset(&cemdcmd, 0, sizeof(cemdcmd));
345  cemdcmd.magic = fn_le32(0x06022009);
346  cemdcmd.tag = fn_le32(dev->parent->audio_tag);
347  cemdcmd.arg1 = fn_le32(0);
348  cemdcmd.cmd = fn_le32(0x00000133);
349  cemdcmd.arg2 = fn_le32(0x00064014); // This is the length of the CEMD data.
350  FN_INFO("Starting CEMD data upload:\n");
351  int res;
352  int transferred;
353  res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred);
354  if(res != 0 || transferred != sizeof(cemdcmd)) {
355  FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(cemdcmd));
356  return -1;
357  }
358  res = get_reply(dev);
359  dev->parent->audio_tag++;
360 
361  const char* cemd_filename = "cemd_data.bin";
362  FILE* cf = fopen(cemd_filename, "r");
363  if(cf == NULL) {
364  FN_ERROR("upload_cemd_data: Failed to open %s: error %d", cemd_filename, errno);
365  return errno;
366  }
367  uint32_t addr = 0x00000000;
368  int read = 0;
369  unsigned char page[0x4000];
370  do {
371  read = fread(page, 1, 0x4000, cf);
372  if(read <= 0) {
373  break;
374  }
375  //LOG("");
376  cemdcmd.tag = fn_le32(dev->parent->audio_tag);
377  cemdcmd.arg1 = fn_le32(read);
378  cemdcmd.cmd = fn_le32(0x134);
379  cemdcmd.arg2 = fn_le32(addr);
380  FN_INFO("About to send: ");
381  dump_cemd_cmd(ctx, cemdcmd);
382  // Send it off!
383  res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred);
384  if(res != 0 || transferred != sizeof(cemdcmd)) {
385  FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)sizeof(cemdcmd));
386  return -1;
387  }
388  int bytes_sent = 0;
389  while(bytes_sent < read) {
390  int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent);
391  res = fnusb_bulk(dev, 1, &page[bytes_sent], to_send, &transferred);
392  if(res != 0 || transferred != to_send) {
393  FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send);
394  return -1;
395  }
396  bytes_sent += to_send;
397  }
398  res = get_reply(dev);
399  addr += (uint32_t)read;
400  dev->parent->audio_tag++;
401  } while (read > 0);
402  fclose(cf);
403  cf = NULL;
404 
405  cemdcmd.tag = fn_le32(dev->parent->audio_tag);
406  cemdcmd.arg1 = fn_le32(0); // bytes = 0
407  cemdcmd.cmd = fn_le32(0x135);
408  cemdcmd.arg2 = fn_le32(0x00064000); // mimicing the USB logs. This is the # of bytes of actual CEMD data after the 20-byte CEMD header.
409  FN_INFO("Finishing CEMD data upload...\n");
410  res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred);
411  if(res != 0 || transferred != sizeof(cemdcmd)) {
412  FN_ERROR("upload_cemd_data(): Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(cemdcmd));
413  return -1;
414  }
415  res = get_reply(dev);
416  dev->parent->audio_tag++;
417  FN_INFO("CEMD data uploaded successfully.\n");
418  return 0;
419 }
FN_INTERNAL int upload_cemd_data(fnusb_dev *dev)
Definition: loader.c:340
FN_INTERNAL int fnusb_bulk(fnusb_dev *dev, uint8_t endpoint, uint8_t *data, int len, int *transferred)
Definition: usb_libusb10.c:828
uint32_t arg2
Definition: loader.h:58
freenect_context * parent
uint32_t base_addr
Definition: loader.h:48
uint32_t magic
Definition: loader.h:34
uint32_t tag
Definition: loader.h:35
uint32_t magic
Definition: loader.h:43
#define FN_ERROR(...)
uint32_t tag
Definition: loader.h:55
uint32_t cmd
Definition: loader.h:57
FN_INTERNAL int upload_firmware(fnusb_dev *dev, char *filename)
Definition: loader.c:125
uint32_t addr
Definition: loader.h:38
#define fn_le16(x)
static void dump_cemd_cmd(freenect_context *ctx, cemdloader_command cmd)
Definition: loader.c:43
uint32_t arg1
Definition: loader.h:56
uint16_t ver_release
Definition: loader.h:46
uint16_t ver_major
Definition: loader.h:45
static int get_reply(fnusb_dev *dev)
Definition: loader.c:50
uint16_t ver_patch
Definition: loader.h:47
uint32_t entry_addr
Definition: loader.h:50
uint32_t cmd
Definition: loader.h:37
uint32_t magic
Definition: loader.h:54
uint32_t size
Definition: loader.h:49
void dump(char type, uint32_t timestamp, void *data, int data_size)
Definition: record.c:102
FN_INTERNAL int upload_firmware_from_memory(fnusb_dev *dev, unsigned char *fw_from_mem, unsigned int fw_size_in_btyes)
Definition: loader.c:233
freenect_device * parent
Definition: usb_libusb10.h:69
uint16_t ver_minor
Definition: loader.h:44
uint32_t bytes
Definition: loader.h:36
static void dump_bl_cmd(freenect_context *ctx, bootloader_command cmd)
Definition: loader.c:36
static int check_version_string(fnusb_dev *dev)
Definition: loader.c:82
static freenect_context * ctx
#define FN_INTERNAL
unsigned int uint32_t
#define FN_INFO(...)
#define fn_le32(x)


libfreenect
Author(s): Hector Martin, Josh Blake, Kyle Machulis, OpenKinect community
autogenerated on Thu Jun 6 2019 19:25:38