diff options
Diffstat (limited to 'src/mkii.c')
-rw-r--r-- | src/mkii.c | 372 |
1 files changed, 352 insertions, 20 deletions
@@ -17,42 +17,351 @@ */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <arpa/inet.h> + #include "mkii.h" #include "global.h" #include "image.h" #include "device.h" #include "usb-device.h" +#define MKII_OUT 0x8810001B +#define MKII_IN 0x8800101B + +#define MKII_PING 0x00 +#define MKII_GET 0x01 +#define MKII_TELL 0x02 +#define MKII_REBOOT 0x0C +#define MKII_RESPONCE 0x20 + +struct mkii_message { + uint32_t header; + uint16_t size; + uint16_t zero; + uint8_t num; + uint8_t type; + char data[]; +} __attribute__((__packed__)); + + +static int mkii_send_receive(usb_dev_handle * udev, uint8_t type, struct mkii_message * in_msg, size_t data_size, struct mkii_message * out_msg, size_t out_size) { + + int ret; + static uint8_t number = 0; + + in_msg->header = MKII_OUT; + in_msg->size = htons(data_size + 4); + in_msg->zero = 0; + in_msg->num = number++; + in_msg->type = type; + + ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)in_msg, data_size + sizeof(*in_msg), 5000); + if ( ret < 0 ) + return ret; + if ( (size_t)ret != data_size + sizeof(*in_msg) ) + return -1; + + ret = usb_bulk_read(udev, USB_READ_EP, (char *)out_msg, out_size, 5000); + if ( ret < 0 ) + return ret; + + if ( out_msg->header != MKII_IN ) + return -1; + + if ( out_msg->type != (type | MKII_RESPONCE) ) + return -1; + + if ( (size_t)ret < sizeof(*out_msg) ) + return -1; + + if ( ntohs(out_msg->size) != ret - sizeof(*out_msg) + 4 ) + return -1; + + return ret - sizeof(*out_msg); + +} + int mkii_init(struct usb_device_info * dev) { - ERROR("Mk II protocol is not implemented yet"); - (void)dev; - return -1; + char buf[2048]; + struct mkii_message * msg; + enum device device; + int ret; + char * newptr; + char * ptr; + enum image_type type; + + printf("Initializing Mk II protocol...\n"); + + msg = (struct mkii_message *)buf; + + ret = mkii_send_receive(dev->udev, MKII_PING, msg, 0, msg, sizeof(buf)); + if ( ret != 0 ) + ERROR_RETURN("Cannot ping device", -1); + + memcpy(msg->data, "/update/protocol_version", sizeof("/update/protocol_version")-1); + ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/update/protocol_version")-1, msg, sizeof(buf)); + if ( ret < 2 || msg->data[0] != 0 ) + ERROR_RETURN("Cannot get Mk II protocol version", -1); + + msg->data[ret] = 0; + + if ( ret == 2 && msg->data[1] == 0x32 ) + dev->data |= MKII_SUPPORT_SW_RELEASE; + + printf("Detected Mk II protocol version: %s\n", msg->data); + + memcpy(msg->data, "/update/host_protocol_version\x00\x32", sizeof("/update/host_protocol_version\x00\x32")-1); + ret = mkii_send_receive(dev->udev, MKII_TELL, msg, sizeof("/update/host_protocol_version\x00\x32")-1, msg, sizeof(buf)); + if ( ret != 1 || msg->data[0] != 0 ) + ERROR_RETURN("Cannot send our protocol version", -1); + + device = mkii_get_device(dev); + + if ( ! dev->device ) + dev->device = device; + + if ( dev->device && device && dev->device != device ) { + ERROR("Device mishmash, expected %s, got %s", device_to_string(dev->device), device_to_string(device)); + return -1; + } + + dev->hwrev = mkii_get_hwrev(dev); + + memcpy(msg->data, "/update/supported_images", sizeof("/update/supported_images")-1); + ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/update/supported_images")-1, msg, sizeof(buf)); + if ( ret < 2 || msg->data[0] != 0 ) + ERROR_RETURN("Cannot get supported image types", -1); + + msg->data[ret] = 0; + ptr = msg->data + 1; + + printf("Supported images by current device configuration:"); + + while ( ptr && *ptr ) { + newptr = strchr(ptr, ','); + if ( newptr ) { + *newptr = 0; + ++newptr; + } + type = image_type_from_string(ptr); + if ( type != IMAGE_UNKNOWN ) { + dev->data |= (1UL << type); + printf(" %s", ptr); + } + ptr = newptr; + } + + printf("\n"); + + memset(buf, 0, sizeof(buf)); + if ( usb_device(dev->udev)->descriptor.bNumConfigurations >= 1 ) + usb_get_string_simple(dev->udev, usb_device(dev->udev)->config[0].iConfiguration, buf, sizeof(buf)); + if ( strncmp(buf, "Firmware Upgrade Configuration", sizeof("Firmware Upgrade Configuration")) == 0 ) + dev->data |= MKII_UPDATE_MODE; + + printf("Mode: %s\n", (dev->data & MKII_UPDATE_MODE) ? "Update" : "PC Suite"); + + return 0; } enum device mkii_get_device(struct usb_device_info * dev) { - ERROR("Not implemented yet"); - (void)dev; - return DEVICE_UNKNOWN; + char buf[2048]; + struct mkii_message * msg; + int ret; + + msg = (struct mkii_message *)buf; + + memcpy(msg->data, "/device/product_code", sizeof("/device/product_code")-1); + ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/device/product_code")-1, msg, sizeof(buf)); + if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 ) + return DEVICE_UNKNOWN; + + msg->data[ret] = 0; + return device_from_string((char *)msg->data+1); } int mkii_flash_image(struct usb_device_info * dev, struct image * image) { + char buf1[512]; + char buf[2048]; + struct mkii_message * msg1; + struct mkii_message * msg; + char * ptr; + const char * type; + uint8_t len; + uint16_t hash; + uint32_t size; + int ret; + ERROR("Not implemented yet"); - (void)dev; - (void)image; return -1; + if ( ! ( dev->data & (1UL << image->type) ) ) { + ERROR("Flashing image %s is not supported in current device configuration", image_type_to_string(image->type)); + return -1; + } + + msg = (struct mkii_message *)buf; + msg1 = (struct mkii_message *)buf1; + ptr = msg->data; + + /* Signature */ + memcpy(ptr, "\x2E\x19\x01\x01", 4); + ptr += 4; + + /* Space */ + memcpy(ptr, "\x00", 1); + ptr += 1; + + /* Hash */ + hash = htons(image->hash); + memcpy(ptr, &hash, 2); + ptr += 2; + + /* Type */ + type = image_type_to_string(image->type); + if ( ! type ) + ERROR_RETURN("Unknown image type", -1); + memset(ptr, 0, 12); + strncpy(ptr, type, 12); + ptr += 12; + + /* Size */ + size = htonl(image->size); + memcpy(ptr, &size, 4); + ptr += 4; + + /* Space */ + memcpy(ptr, "\x00\x00\x00\x00", 4); + ptr += 4; + + /* Device & hwrev */ + if ( image->devices ) { + + int i; + uint8_t len; + char buf[9]; + char ** bufs = NULL; + struct device_list * device = image->devices; + + while ( device ) { + if ( device->device == dev->device && hwrev_is_valid(device->hwrevs, dev->hwrev) ) + break; + device = device->next; + } + + if ( device ) + bufs = device_list_alloc_to_bufs(device); + + if ( bufs ) { + + memset(buf, 0, sizeof(buf)); + snprintf(buf, 8+1, "%d", dev->hwrev); + + for ( i = 0; bufs[i]; ++i ) { + len = ((uint8_t*)bufs[i])[0]; + if ( MEMMEM(bufs[i]+1, len, buf, strlen(buf)) ) + break; + } + + if ( bufs[i] ) { + /* Device & hwrev string header */ + memcpy(ptr, "\x32", 1); + ptr += 1; + /* Device & hwrev string size */ + memcpy(ptr, &len, 1); + ptr += 1; + /* Device & hwrev string */ + memcpy(ptr, bufs[i]+1, len); + ptr += len; + } + + free(bufs); + + } + + } + + /* Version */ + if ( image->version ) { + len = strnlen(image->version, 255) + 1; + /* Version string header */ + memcpy(ptr, "\x31", 1); + ptr += 1; + /* Version string size */ + memcpy(ptr, &len, 1); + ptr += 1; + /* Version string */ + memcpy(ptr, image->version, len); + ptr += len; + } + + /* append layout subsection */ + if ( image->layout ) { + len = strlen(image->layout); + /* Layout header */ + memcpy(ptr, "\x33", 1); + ptr += 1; + /* Layout size */ + memcpy(ptr, &len, 1); + ptr += 1; + /* Layout string */ + memcpy(ptr, image->layout, len); + ptr += len; + } + + /* end */ + memcpy(ptr, "\x00", 1); + ptr += 1; + + ret = mkii_send_receive(dev->udev, 0x03, msg1, 0, msg1, sizeof(buf1)); + if ( ret != 1 || msg1->data[0] != 0 ) + return -1; + + ret = mkii_send_receive(dev->udev, 0x04, msg, ptr - msg->data, msg, sizeof(buf)); + if ( ret != 9 ) + return -1; + + /* TODO: send image itself */ + + return 0; + } -int mkii_reboot_device(struct usb_device_info * dev) { +int mkii_reboot_device(struct usb_device_info * dev, int update) { - ERROR("Not implemented yet"); - (void)dev; - return -1; + char buf[2048]; + struct mkii_message * msg; + const char * str; + int len; + int ret; + + msg = (struct mkii_message *)buf; + + if ( update ) { + printf("Rebooting device to Update mode...\n"); + len = sizeof("reboot=update"); + str = "reboot=update"; + } else { + printf("Rebooting device...\n"); + len = sizeof("reboot"); + str = "reboot"; + } + + memcpy(msg->data, str, len); + ret = mkii_send_receive(dev->udev, MKII_REBOOT, msg, len, msg, sizeof(buf)); + if ( ret != 1 || msg->data[0] != 0 ) + ERROR_RETURN("Cannot send reboot command", -1); + + return 0; } @@ -128,9 +437,19 @@ int mkii_set_rd_flags(struct usb_device_info * dev, const char * flags) { int16_t mkii_get_hwrev(struct usb_device_info * dev) { - ERROR("Not implemented yet"); - (void)dev; - return -1; + char buf[2048]; + struct mkii_message * msg; + int ret; + + msg = (struct mkii_message *)buf; + + memcpy(msg->data, "/device/hw_build", sizeof("/device/hw_build")-1); + ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/device/hw_build")-1, msg, sizeof(buf)); + if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 ) + ERROR_RETURN("Cannot get hw revision", -1); + + msg->data[ret] = 0; + return atoi(msg->data+1); } @@ -202,11 +521,24 @@ int mkii_set_nolo_ver(struct usb_device_info * dev, const char * ver) { int mkii_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size) { - ERROR("Not implemented yet"); - (void)dev; - (void)ver; - (void)size; - return -1; + char buf[2048]; + struct mkii_message * msg; + int ret; + + if ( ! ( dev->data & MKII_SUPPORT_SW_RELEASE ) ) + return -1; + + msg = (struct mkii_message *)buf; + + memcpy(msg->data, "/version/sw_release", sizeof("/version/sw_release")-1); + ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/version/sw_release")-1, msg, sizeof(buf)); + if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 ) + ERROR_RETURN("Cannot get sw release", -1); + + msg->data[ret] = 0; + strncpy(ver, msg->data+1, size); + ver[size-1] = 0; + return strlen(ver); } |