From: Drew Fisher Date: Sun, 11 Sep 2011 18:35:19 +0000 (+0200) Subject: Initial import of kinect_upload_fw X-Git-Tag: v0.1~25 X-Git-Url: https://git.ao2.it/kinect-audio-setup.git/commitdiff_plain/f7512fc58f5b70f8111abd3c9e738ddaf8cdb753 Initial import of kinect_upload_fw kinect_upload_fw is a program to upload the Usb Audio Class firmware to the Microsoft Kinect sensor device. Before the firmware is uploaded the device shows up as a generic usb device with a bulk endpoint, after the firmware upload a reenumeration takes place and a Usb Audio Class device becomes available. --- f7512fc58f5b70f8111abd3c9e738ddaf8cdb753 diff --git a/kinect_upload_fw/Makefile b/kinect_upload_fw/Makefile new file mode 100644 index 0000000..655bd12 --- /dev/null +++ b/kinect_upload_fw/Makefile @@ -0,0 +1,14 @@ +CFLAGS += $(shell pkg-config --cflags libusb-1.0) +LDFLAGS += $(shell pkg-config --libs libusb-1.0) + +PREFIX ?= /usr/local +bindir = $(PREFIX)/sbin + +kinect_upload_fw: kinect_upload_fw.o + +install: kinect_upload_fw + install -d $(DESTDIR)$(bindir) + install -m 755 kinect_upload_fw $(DESTDIR)$(bindir) + +clean: + rm -rf *~ *.o kinect_upload_fw diff --git a/kinect_upload_fw/kinect_upload_fw.c b/kinect_upload_fw/kinect_upload_fw.c new file mode 100644 index 0000000..1466ccd --- /dev/null +++ b/kinect_upload_fw/kinect_upload_fw.c @@ -0,0 +1,221 @@ +/* + * Copyright 2011 Drew Fisher . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL DREW FISHER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Drew Fisher. + */ + +#include +#include +#include +#include +#include + +static libusb_device_handle *dev; +int seq; + +typedef struct { + uint32_t magic; + uint32_t seq; + uint32_t bytes; + uint32_t cmd; + uint32_t write_addr; + uint32_t unk; +} bootloader_command; + +typedef struct { + uint32_t magic; + uint32_t seq; + uint32_t status; +} status_code; + +#define LOG(...) printf(__VA_ARGS__) +#define fn_le32(x) (x) +// TODO: support architectures that aren't little-endian + +void dump_bl_cmd(bootloader_command cmd) { + int i; + for(i = 0; i < 24; i++) + LOG("%02X ", ((unsigned char*)(&cmd))[i]); + LOG("\n"); +} + +int get_first_reply() { + unsigned char buffer[512]; + int res; + int transferred; + res = libusb_bulk_transfer(dev, 0x81, buffer, 512, &transferred, 0); + if(res != 0 ) { + LOG("Error reading first reply: %d\ttransferred: %d (expected %d)\n", res, transferred, 0x60); + return res; + } + LOG("Reading first reply: "); + int i; + for(i = 0; i < transferred; ++i) { + LOG("%02X ", buffer[i]); + } + LOG("\n"); + return res; +} + + +int get_reply() { + unsigned char dump[512]; + status_code buffer = ((status_code*)dump)[0]; + int res; + int transferred; + res = libusb_bulk_transfer(dev, 0x81, (unsigned char*)&buffer, 512, &transferred, 0); + if(res != 0 || transferred != sizeof(status_code)) { + LOG("Error reading reply: %d\ttransferred: %d (expected %d)\n", res, transferred, sizeof(status_code)); + return res; + } + if(fn_le32(buffer.magic) != 0x0a6fe000) { + LOG("Error reading reply: invalid magic %08X\n",buffer.magic); + return -1; + } + if(fn_le32(buffer.seq) != seq) { + LOG("Error reading reply: non-matching sequence number %08X (expected %08X)\n", buffer.seq, seq); + return -1; + } + if(fn_le32(buffer.status) != 0) { + LOG("Notice reading reply: last uint32_t was nonzero: %d\n", buffer.status); + } + + LOG("Reading reply: "); + int i; + for(i = 0; i < transferred; ++i) { + LOG("%02X ", ((unsigned char*)(&buffer))[i]); + } + LOG("\n"); + + return res; +} + +int main(int argc, char** argv) { + char* filename = "firmware.bin"; + if (argc == 2) { + filename = argv[1]; + } + FILE* fw = fopen(filename, "r"); + if(fw == NULL) { + fprintf(stderr, "Failed to open %s: error %d", filename, errno); + return errno; + } + + libusb_init(NULL); + libusb_set_debug(0,3); + dev = libusb_open_device_with_vid_pid(NULL, 0x045e, 0x02ad); + + if(dev == NULL) { + printf("Couldn't open device.\n"); + return 1; + } + + libusb_set_configuration(dev, 1); + libusb_claim_interface(dev, 0); + + seq = 1; + + bootloader_command cmd; + cmd.magic = fn_le32(0x06022009); + cmd.seq = fn_le32(seq); + cmd.bytes = fn_le32(0x60); + cmd.cmd = fn_le32(0); + cmd.write_addr = fn_le32(0x15); + cmd.unk = fn_le32(0); + + LOG("About to send: "); + dump_bl_cmd(cmd); + int res; + int transferred; + + res = libusb_bulk_transfer(dev, 1, (unsigned char*)&cmd, sizeof(cmd), &transferred, 0); + if(res != 0 || transferred != sizeof(cmd)) { + LOG("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, sizeof(cmd)); + goto cleanup; + } + res = get_first_reply(); // This first one doesn't have the usual magic bytes at the beginning, and is 96 bytes long - much longer than the usual 12-byte replies. + res = get_reply(); // I'm not sure why we do this twice here, but maybe it'll make sense later. + seq++; + + uint32_t addr = 0x00080000; + char page[0x4000]; + int read; + do { + read = fread(page, 1, 0x4000, fw); + if(read <= 0) { + break; + } + //LOG(""); + cmd.seq = fn_le32(seq); + cmd.bytes = fn_le32(read); + cmd.cmd = fn_le32(0x03); + cmd.write_addr = fn_le32(addr); + LOG("About to send: "); + dump_bl_cmd(cmd); + // Send it off! + res = libusb_bulk_transfer(dev, 1, (unsigned char*)&cmd, sizeof(cmd), &transferred, 0); + if(res != 0 || transferred != sizeof(cmd)) { + LOG("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, sizeof(cmd)); + goto cleanup; + } + int bytes_sent = 0; + while(bytes_sent < read) { + int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent); + res = libusb_bulk_transfer(dev, 1, &page[bytes_sent], to_send, &transferred, 0); + if(res != 0 || transferred != to_send) { + LOG("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send); + goto cleanup; + } + bytes_sent += to_send; + } + res = get_reply(); + + addr += (uint32_t)read; + seq++; + } while (read > 0); + + cmd.seq = fn_le32(seq); + cmd.bytes = fn_le32(0); + cmd.cmd = fn_le32(0x04); + cmd.write_addr = fn_le32(0x00080030); + dump_bl_cmd(cmd); + res = libusb_bulk_transfer(dev, 1, (unsigned char*)&cmd, sizeof(cmd), &transferred, 0); + if(res != 0 || transferred != sizeof(cmd)) { + LOG("Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, sizeof(cmd)); + goto cleanup; + } + res = get_reply(); + seq++; + // Now the device reenumerates. + +cleanup: + libusb_close(dev); + libusb_exit(NULL); + return 0; +} +