/*
 * displaylink userspace controller demo 0.0.1
 * written 2008/09 by floe at butterbrot.org
 * in cooperation with chrisly at platon42.de
 * this code is released as public domain.
 *
 * this is so experimental that the warranty shot itself.
 * so don't expect any.
 *
 * build with "g++ -ggdb -Wall -o displaylink displaylink.c -lusb"
 *
 */

#include <usb.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/******************* ENCRYPTION STUFF **********************/

unsigned char nullkey1[] = { 0x57, 0xCD, 0xDC, 0xA7, 0x1C, 0x88, 0x5E, 0x15, 0x60, 0xFE, 0xC6, 0x97, 0x16, 0x3D, 0x47, 0xF2 };
unsigned char nullkey2[] = { 0x47, 0x3D, 0x16, 0x97, 0xC6, 0xFE, 0x60, 0x15, 0x5E, 0x88, 0x1C, 0xA7, 0xDC, 0xB7, 0x6F, 0xF2 };
unsigned char nullkey3[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x18,0xF0 };

uint8_t  keybuffer[0x11000];
uint16_t ofsbuffer[0x1000];

// x^12+x^11+x^3+x^2+x+1 = 0001 1000 0000 1111 = 0x180F
int dl_crc12( unsigned char* data, int len) {
	int rem = 0;
	for (int i = 0; i < len; i++) {
		for (int j = 0; j < 8; j++) {
			rem = (rem << 1) | ((data[i] >> j) & 0x01);
			if (rem & 0x1000) rem = rem ^ 0x180F;
		}
	}
	return rem;
}


void dl_generate_key( uint8_t key[0x11000], uint16_t map[0x1000] ) {

  int coeffs[0x20];
  int count = 0;

  // loop1:
  for (int i = 0; i < 0x20; i++) {

    int tmp = 1 << i;
    if (!(tmp & 0x0829)) continue;

    coeffs[count] = i;
    count++;
  }

  int val = 0x01;

  // loop2:
  for (int i = 0; i < 0x11000; i++) {

    key[i] = val;
    if (i < 0x1000) map[val] = i;

    // loop3:
    for ( int j = 8; j > 0; j--) {

      int res = 0;

			// loop4:
      for (int k = 0; k < count; k++) {
        int coeff = coeffs[k];
        coeff = val >> coeff;
        res = res ^ coeff;
      }

      res = res & 1;
      res = res ^ (2*val);
      val = res & 0xFFF;
    }
  }
}


/******************* INITIALIZATION STUFF *****************/

uint8_t dl_peek( int addr, usb_dev_handle* handle, int timeout = 1000 ) {
	uint8_t buf[1];
	usb_control_msg( handle, 0xC0, 0x04, 0x00, addr, (char*)buf, 1, timeout );
	return buf[0];
}

void dl_poke( int addr, uint8_t value, usb_dev_handle* handle, int timeout = 1000 ) {
	usb_control_msg( handle, 0x40, 0x03, 0x00, addr, (char*)&value, 1, timeout );
}

int dl_poll( usb_dev_handle* handle, int timeout = 1000 ) {
	uint8_t buf[4];
	usb_control_msg( handle, 0xC0, 0x06, 0x00, 0x00, (char*)buf, 4, timeout );
	return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
}

void dl_set_key( uint8_t key[16], usb_dev_handle* handle, int timeout = 1000 ) {
	usb_control_msg( handle, 0x40, 0x12, 0x00, 0x00, (char*)key, 16, timeout );
}

void dl_blink( usb_dev_handle* handle, int timeout = 1000 ) {
	usb_control_msg( handle, 0x40, 0x14, 0x00, 0x00, NULL, 0, timeout );
}

void dl_get_edid( uint8_t edid[128], usb_dev_handle* handle, int timeout = 1000 ) {
	uint8_t buf[64];
	int offset = 0;
	usb_control_msg( handle, 0xC0, 0x02, offset<<8, 0xA1, (char*)buf, 64, timeout ); memcpy( edid+offset, buf+1, 63 ); offset += 63;
	usb_control_msg( handle, 0xC0, 0x02, offset<<8, 0xA1, (char*)buf, 64, timeout ); memcpy( edid+offset, buf+1, 63 ); offset += 63;
	usb_control_msg( handle, 0xC0, 0x02, offset<<8, 0xA1, (char*)buf,  3, timeout ); memcpy( edid+offset, buf+1,  2 );
}

/******************* COMMAND BUFFER ***********************/

typedef struct {
	uint8_t* buffer;
	int pos, size;
} dl_cmdstream;


inline void create( dl_cmdstream* cs, int size ) {
	cs->buffer = (uint8_t*)malloc( size );
	cs->size = size;
	cs->pos = 0;
}

inline void destroy( dl_cmdstream* cs ) {
	free( cs->buffer );
	cs->size = 0;
}

inline void send( dl_cmdstream* cs, usb_dev_handle* handle, int ep = 1, int timeout = 1000 ) {
	usb_bulk_write( handle, ep, (char*)cs->buffer, cs->pos, timeout );
	cs->pos = 0;
}

inline void insertb( dl_cmdstream* cs, uint8_t val ) {
	cs->buffer[cs->pos++] = val;
}

inline void insertw( dl_cmdstream* cs, uint16_t val ) {
	insertb( cs, (val >> 8) & 0xFF );
	insertb( cs, (val     ) & 0xFF );
}

inline void inserta( dl_cmdstream* cs, uint32_t address ) {
	insertb( cs, (address >> 16) & 0xFF );
	insertb( cs, (address >>  8) & 0xFF );
	insertb( cs, (address      ) & 0xFF );
}

inline void insertd( dl_cmdstream* cs, uint32_t val ) {
	insertb( cs, (val >> 24) & 0xFF );
	insertb( cs, (val >> 16) & 0xFF );
	insertb( cs, (val >>  8) & 0xFF );
	insertb( cs, (val      ) & 0xFF );
}

inline void insert( dl_cmdstream* cs, int size, uint8_t* buf ) {
	memcpy( cs->buffer+cs->pos, buf, size );
	cs->pos += size;
}


/******************* COMMANDS *****************************/

#define DL_SOC 0xAF // start-of-command token


/******************* MISC COMMANDS ************************/

void dl_unknown_command( dl_cmdstream* cs ) {
	insertb( cs, DL_SOC );
	insertb( cs,   0x40 );
	insertb( cs,   0x0B );
}

void dl_sync_command( dl_cmdstream* cs ) {
	insertb( cs, DL_SOC );
	insertb( cs,   0xA0 );
}

void dl_decomp_table_command( dl_cmdstream* cs, int size, uint8_t* buf ) {

	if ((size % 9) != 0) return;
	int count = size / 9;

	insertb( cs, DL_SOC );
	insertb( cs,   0xE0 );

	insertd( cs, 0x263871CD ); // magic number
 	insertd( cs, count );      // count of 9-byte chunks

	insert( cs, size, buf );   // count * 9 bytes

	dl_sync_command( cs );
}


/******************* REGISTER COMMANDS ********************/

#define DL_REG_COLORDEPTH   0x00 // 0 = 16 bit, 1 = 24 bit
// 0x01 - 0x0E unknown
#define DL_REG_XRES_MSB     0x0F
#define DL_REG_XRES_LSB     0x10
// 0x11 - 0x16 unknown
#define DL_REG_YRES_MSB     0x17
#define DL_REG_YRES_LSB     0x18
// 0x19 - 0x1C unknown
// 0x1D - 0x1E unused
#define DL_REG_BLANK_SCREEN 0x1F // 0 = normal operation, 1 = blank screen
// 0x20 - 0xFE unused
#define DL_REG_SYNC         0xFF // 0 = hold register updates, 0xFF = resume

// The unknown registers very likely contain pixel clock, sync polarity etc.
// While the mapping hasn't been found yet, some default register sets for
// standard resolutions are given below.

uint8_t dl_register_init_640[]  = { 0x00, 0x99, 0x30, 0x26, 0x94, 0x60, 0xa9, 0xce, 0x60, 0x07, 0xb3, 0x0f, 0x79, 0xff, 0xff, 0x02, 0x80, 0x83, 0xbc, 0xff, 0xfc, 0xff, 0xff, 0x01, 0xe0, 0x01, 0x02, 0xab, 0x13 };
uint8_t dl_register_init_800[]  = { 0x00, 0x20, 0x3c, 0x7a, 0xc9, 0x93, 0x60, 0xc8, 0xc7, 0x70, 0x53, 0xff, 0xff, 0x21, 0x27, 0x03, 0x20, 0x91, 0x8f, 0xff, 0xff, 0xff, 0xf2, 0x02, 0x58, 0x01, 0x02, 0x40, 0x1f };
uint8_t dl_register_init_1024[] = { 0x00, 0x36, 0x18, 0xd5, 0x10, 0x60, 0xa9, 0x7b, 0x33, 0xa1, 0x2b, 0x27, 0x32, 0xff, 0xff, 0x04, 0x00, 0xd9, 0x9a, 0xff, 0xca, 0xff, 0xff, 0x03, 0x00, 0x04, 0x03, 0xc8, 0x32 };
uint8_t dl_register_init_1280[] = { 0x00, 0x98, 0xf8, 0x0d, 0x57, 0x2a, 0x55, 0x4d, 0x54, 0xca, 0x0d, 0xff, 0xff, 0x94, 0x43, 0x05, 0x00, 0x9a, 0xa8, 0xff, 0xff, 0xff, 0xf9, 0x04, 0x00, 0x04, 0x02, 0x60, 0x54 };
uint8_t dl_register_init_U70[]  = { 0x00, 0x20, 0x3c, 0x7a, 0xc9, 0xf2, 0x6c, 0x48, 0xf9, 0x70, 0x53, 0xff, 0xff, 0x21, 0x27, 0x03, 0x20, 0x91, 0xf3, 0xff, 0xff, 0xff, 0xf9, 0x01, 0xe0, 0x01, 0x02, 0xc8, 0x19 };

/*24-bit:
640x480:    01    99 30 26 94 60 a9 ce 60 07 b3 0f 79 ff ff  02 80  83 bc ff fc ff ff  01 e0  01 02 ab 13
1280x..:    01    98 f8 0d 57 2a 55 4d 54 ca 0d ff ff 94 43  05 00  9a a8 ff ff ff f9  04 00  04 02 60 54
*/

void dl_set_register( dl_cmdstream* cs, uint8_t reg, uint8_t val ) {
	insertb( cs, DL_SOC );
	insertb( cs,   0x20 );
	insertb( cs,    reg );
	insertb( cs,    val );
}

void dl_set_registers( dl_cmdstream* cs, uint8_t values[0x1D] ) {
	dl_set_register( cs, DL_REG_SYNC, 0x00 );
	for (int i = 0; i < 0x1D; i++)
		dl_set_register( cs, i, values[i] );
	dl_set_register( cs, DL_REG_SYNC, 0xFF );
}


/****************** ADDRESS REGISTERS *********************/

#define DL_ADDR_FB16_START  0x20 // 16-bit mode, color MSBs, RGB 565
#define DL_ADDR_FB16_STRIDE 0x23
#define DL_ADDR_FB8_START   0x26 // additional 8 bit for 24-bit mode, color LSBs, RGB 323?
#define DL_ADDR_FB8_STRIDE  0x29

void dl_set_address( dl_cmdstream* cs, uint8_t reg, int address ) {
	dl_set_register( cs, reg+0, (address >> 16) & 0xFF );
	dl_set_register( cs, reg+1, (address >>  8) & 0xFF );
	dl_set_register( cs, reg+2, (address      ) & 0xFF );
}

void dl_set_offsets( dl_cmdstream* cs, int start16, int stride16, int start8, int stride8 ) {
	dl_set_register( cs, DL_REG_SYNC, 0x00 );
	dl_set_address( cs, DL_ADDR_FB16_START,  start16  );
	dl_set_address( cs, DL_ADDR_FB16_STRIDE, stride16 );
	dl_set_address( cs, DL_ADDR_FB8_START,   start8   );
	dl_set_address( cs, DL_ADDR_FB8_STRIDE,  stride8  );
	dl_set_register( cs, DL_REG_SYNC, 0xFF );
}


/******************* GRAPHICS COMMANDS ********************/

#define DL_GFX_BASE 0x60 // base graphics command
#define DL_GFX_WORD 0x08 // word-mode flag
#define DL_GFX_COMP 0x10 // compressed-mode flag

#define DL_GFX_WRITE (DL_GFX_BASE | 0x00) // write memory
#define DL_GFX_RLE   (DL_GFX_BASE | 0x01) // write RLE-encoded data
#define DL_GFX_COPY  (DL_GFX_BASE | 0x02) // internal copy

void dl_gfx_command( dl_cmdstream* cs, uint8_t cmd, int addr, uint8_t count ) {
	insertb( cs, DL_SOC );
	insertb( cs,    cmd );
	inserta( cs,   addr );
	insertb( cs,  count );
}

void dl_gfx_write( dl_cmdstream* cs, int addr, uint8_t count, uint8_t* data ) {
	dl_gfx_command( cs, DL_GFX_WRITE | DL_GFX_WORD, addr, count );
	int pcount = (count == 0) ? 256 : count;
	insert( cs, pcount*2, data );
}

typedef struct {
	uint8_t count;
	uint16_t value;
} rle_word;

void dl_gfx_rle( dl_cmdstream* cs, int addr, uint8_t count, rle_word* rs ) {

	dl_gfx_command( cs, DL_GFX_RLE | DL_GFX_WORD, addr, count );

	int pcount = (count == 0) ? 256 : count;
	int i = 0;
	rle_word* cur = rs;

	while (i < pcount) {
		insertb( cs, cur->count );
		insertw( cs, cur->value );
		i += (cur->count == 0) ? 256: cur->count;
		cur++;
	}
}

void dl_gfx_copy( dl_cmdstream* cs, int src_addr, int dst_addr, uint8_t count ) {
	dl_gfx_command( cs, DL_GFX_COPY | DL_GFX_WORD, dst_addr, count );
  inserta( cs, src_addr );
}


/******************* INITIALIZATION SEQUENCE **************/

static uint8_t dl_decomp_table[] = {
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x60, 0x01, 0x00, 0x00, 0x00, 0x61,
	0x00, 0x00, 0x00, 0x01, 0x23, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x60, 0x05, 0x00, 0x00, 0x00, 0x61,
	0x00, 0x00, 0x00, 0x01, 0x67, 0x00, 0x01, 0x00, 0x01,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0x00, 0x00, 0x00, 0x01, 0x89, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x00, 0x61, 0xab, 0x00, 0x00, 0x00, 0x61,
	0x00, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x60, 0x0f, 0x00, 0x00, 0x00, 0x61,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x01, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x33, 0x00, 0x01, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x44, 0x00, 0x02, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x44, 0x00, 0x02, 0x00, 0x02,
	0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x67, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x67, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x5b, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x01, 0x01, 0xc8, 0x00, 0x00, 0x01, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x5b, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x00, 0x02, 0x5b, 0x00, 0x00, 0x00, 0x01,
	0x00, 0x00, 0x00, 0x02, 0x9a, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0x33, 0x00, 0x01, 0x00, 0x02,
	0x00, 0x00, 0x01, 0x01, 0x2b, 0x00, 0x00, 0x01, 0x02,
	0x00, 0x00, 0x00, 0x02, 0xcc, 0x00, 0x02, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0xdd, 0x00, 0x04, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x02, 0xef, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x01, 0x01, 0xc4, 0x00, 0x00, 0x01, 0x03,
	0x00, 0x29, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03,
	0x00, 0xb7, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0x99, 0x00, 0x04, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0xaa, 0x00, 0x08, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0xbc, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0xde, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0x12, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0x56, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0x78, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0x9a, 0x00, 0x00, 0x00, 0x04,
	0x00, 0xd7, 0x01, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x02, 0x01,
	0x00, 0x00, 0x02, 0x04, 0xbb, 0x00, 0x00, 0x03, 0x04,
	0x00, 0x00, 0x00, 0x04, 0xcc, 0x00, 0x08, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0xdd, 0x00, 0x10, 0x00, 0x04,
	0x00, 0x20, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x04,
	0x00, 0x00, 0x00, 0x04, 0xf0, 0x00, 0x00, 0x00, 0x05,
	0xff, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05,
	0x00, 0x00, 0x00, 0x05, 0x23, 0x00, 0x00, 0x00, 0x05,
	0x08, 0x00, 0x01, 0x00, 0x00, 0x08, 0x20, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x05, 0x45, 0x00, 0x00, 0x00, 0x05,
	0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x00, 0x05,
	0xf8, 0x00, 0x01, 0x00, 0x00, 0xf7, 0xe0, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x05, 0x89, 0x00, 0x00, 0x00, 0x05,
	0xff, 0xff, 0x01, 0x00, 0x00, 0xff, 0xdf, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x05, 0xab, 0x00, 0x00, 0x00, 0x05,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x02, 0x01,
	0x00, 0x00, 0x02, 0x05, 0xcc, 0x00, 0x00, 0x03, 0x05,
	0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00,
	0x00, 0xce, 0x01, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x05, 0xde, 0x00, 0x00, 0x00, 0x05,
	0x00, 0x00, 0x00, 0x05, 0xff, 0x00, 0x10, 0x00, 0x05,
	0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x20, 0x00, 0x06,
	0x08, 0x41, 0x01, 0x00, 0x00, 0x08, 0x21, 0x01, 0x00,
	0x08, 0x61, 0x00, 0x06, 0x12, 0x00, 0x00, 0x00, 0x06,
	0x00, 0x00, 0x00, 0x06, 0x34, 0x00, 0x00, 0x00, 0x06,
	0xf7, 0xbf, 0x01, 0x00, 0x00, 0xf7, 0xdf, 0x01, 0x00,
	0xf7, 0x9f, 0x00, 0x06, 0x56, 0x00, 0x00, 0x00, 0x06,
	0x00, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x00, 0x06,
	0x10, 0x61, 0x00, 0x06, 0x9a, 0x00, 0x00, 0x00, 0x06,
	0x00, 0x41, 0x00, 0x06, 0x9b, 0x00, 0x00, 0x00, 0x06,
	0x08, 0x62, 0x00, 0x06, 0x9c, 0x00, 0x00, 0x00, 0x06,
	0x08, 0x40, 0x00, 0x06, 0x9d, 0x00, 0x00, 0x00, 0x06,
	0xef, 0x9f, 0x00, 0x06, 0xef, 0x00, 0x00, 0x00, 0x06,
	0xff, 0xbf, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x07,
	0xf7, 0x9e, 0x00, 0x06, 0xe1, 0x00, 0x00, 0x00, 0x07,
	0xf7, 0xc0, 0x00, 0x06, 0xe2, 0x00, 0x00, 0x00, 0x07,
	0x00, 0x00, 0x00, 0x07, 0x34, 0x00, 0x00, 0x00, 0x07,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x03, 0x01,
	0x00, 0x00, 0x04, 0x07, 0x55, 0x00, 0x00, 0x06, 0x07,
	0x00, 0x00, 0x00, 0x07, 0x66, 0x00, 0x20, 0x00, 0x07,
	0x00, 0x00, 0x00, 0x07, 0x77, 0x00, 0x40, 0x00, 0x07,
	0x00, 0x00, 0x00, 0x07, 0x88, 0x00, 0x20, 0x00, 0x07,
	0x08, 0x01, 0x01, 0x00, 0x09, 0x10, 0x02, 0x00, 0x07,
	0xef, 0xfe, 0x00, 0x07, 0xab, 0x00, 0x00, 0x00, 0x07,
	0x00, 0x00, 0x00, 0x07, 0xcf, 0xff, 0xff, 0xff, 0x7f,
	0x00, 0x00, 0x00, 0x07, 0xdd, 0xff, 0xe0, 0x00, 0x07,
	0xf7, 0xff, 0x01, 0x00, 0x0e, 0xef, 0xfe, 0x00, 0x07,
	0x10, 0x02, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x08, 0x1f, 0xff, 0xff, 0xff, 0x7f,
	0x00, 0x00, 0x01, 0x00, 0x02, 0x08, 0x41, 0x00, 0x08,
	0x10, 0x41, 0x00, 0x06, 0x93, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x08, 0x45, 0x00, 0x00, 0x00, 0x08,
	0x08, 0x42, 0x00, 0x06, 0x96, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x08, 0x78, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x01, 0x00, 0x09, 0xf7, 0xbf, 0x00, 0x08,
	0xef, 0xbf, 0x00, 0x06, 0xea, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x08, 0xbc, 0x00, 0x00, 0x00, 0x08,
	0xf7, 0xbe, 0x00, 0x06, 0xed, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x08, 0xef, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x03, 0x01,
	0x00, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x06, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x12, 0x00, 0x00, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x33, 0x00, 0x40, 0x00, 0x09,
	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00,
	0x00, 0x00, 0x01, 0x00, 0x04, 0x08, 0x41, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x55, 0x08, 0x01, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x66, 0xf7, 0xff, 0x00, 0x09,
	0x10, 0x42, 0x00, 0x06, 0x99, 0x10, 0x62, 0x00, 0x06,
	0xf8, 0x1f, 0x00, 0x06, 0x99, 0x00, 0x40, 0x00, 0x06,
	0x00, 0x00, 0x01, 0x00, 0x07, 0xf7, 0xbf, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x88, 0xf7, 0xff, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0x99, 0x08, 0x01, 0x00, 0x09,
	0xef, 0xbe, 0x00, 0x06, 0xee, 0xef, 0x9e, 0x00, 0x06,
	0x07, 0xe1, 0x00, 0x06, 0xee, 0xff, 0xc0, 0x00, 0x06,
	0x00, 0x00, 0x01, 0x00, 0x0a, 0x08, 0x41, 0x00, 0x09,
	0xf8, 0x20, 0x00, 0x06, 0x99, 0x07, 0xff, 0x00, 0x06,
	0x08, 0x1f, 0x00, 0x06, 0x9b, 0x00, 0x00, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0xcd, 0x00, 0x00, 0x00, 0x09,
	0x00, 0x1f, 0x00, 0x06, 0x99, 0xf8, 0x01, 0x00, 0x06,
	0xf8, 0x21, 0x00, 0x06, 0x9e, 0x00, 0x00, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x01, 0x00, 0x01, 0xf7, 0xbf, 0x00, 0x0a,
	0x07, 0xe0, 0x00, 0x06, 0xee, 0xf8, 0x01, 0x00, 0x06,
	0xf7, 0xe1, 0x00, 0x06, 0xe2, 0x00, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0x34, 0x00, 0x00, 0x00, 0x0a,
	0xff, 0xe1, 0x00, 0x06, 0xee, 0x07, 0xff, 0x00, 0x06,
	0x07, 0xdf, 0x00, 0x06, 0xe5, 0x00, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0x67, 0x00, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0x89, 0x00, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x05, 0x01,
	0x00, 0x00, 0x08, 0x0a, 0xaa, 0x00, 0x00, 0x0c, 0x0a,
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x0a, 0xbb, 0x08, 0x41, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0xcd, 0x10, 0x02, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0xce, 0xef, 0xfe, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0a, 0xff, 0xf7, 0xbf, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0b, 0x01, 0xef, 0xfe, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0b, 0x02, 0x10, 0x02, 0x00, 0x0b,
	0x00, 0x00, 0x01, 0x00, 0x03, 0x08, 0x41, 0x00, 0x0b,
	0x10, 0x21, 0x00, 0x06, 0x94, 0x00, 0x00, 0x00, 0x0b,
	0xef, 0xff, 0x00, 0x06, 0x95, 0x00, 0x00, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0b, 0x66, 0x00, 0x20, 0x00, 0x0b,
	0x08, 0x22, 0x00, 0x06, 0x97, 0x00, 0x00, 0x00, 0x0b,
	0xf7, 0xfe, 0x00, 0x06, 0x98, 0x00, 0x00, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0b, 0x99, 0x00, 0x20, 0x00, 0x0b,
	0x00, 0x00, 0x01, 0x00, 0x0a, 0xf7, 0xbf, 0x00, 0x0b,
	0xef, 0xdf, 0x00, 0x06, 0xeb, 0x00, 0x00, 0x00, 0x0b,
	0x10, 0x01, 0x00, 0x06, 0xec, 0x00, 0x00, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0b, 0xdd, 0xff, 0xe0, 0x00, 0x0b,
	0xf7, 0xde, 0x00, 0x06, 0xee, 0x00, 0x00, 0x00, 0x0b,
	0x08, 0x02, 0x00, 0x06, 0xef, 0x00, 0x00, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0c, 0x00, 0xff, 0xe0, 0x00, 0x0c,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x05, 0x01,
	0x00, 0x00, 0x08, 0x0c, 0x11, 0x00, 0x00, 0x0c, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0x23, 0x00, 0x00, 0x00, 0x0c,
	0x00, 0x00, 0x01, 0x00, 0x04, 0x10, 0x82, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0x56, 0x00, 0x00, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0x77, 0x10, 0x02, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0x88, 0xef, 0xfe, 0x00, 0x0c,
	0x00, 0x00, 0x01, 0x00, 0x09, 0xef, 0x7e, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0xab, 0x00, 0x00, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0xcc, 0xef, 0xfe, 0x00, 0x0c,
	0x00, 0x00, 0x00, 0x0c, 0xdd, 0x10, 0x02, 0x00, 0x0c,
	0x00, 0x00, 0x01, 0x00, 0x0e, 0x08, 0x41, 0x00, 0x0c,
	0x10, 0x01, 0x00, 0x06, 0x99, 0xf0, 0x1f, 0x00, 0x06,
	0x10, 0x00, 0x00, 0x0a, 0xcc, 0xf0, 0x00, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0c, 0xf0, 0x08, 0x41, 0x00, 0x0d,
	0x08, 0x02, 0x00, 0x06, 0x99, 0xf8, 0x1e, 0x00, 0x06,
	0x00, 0x02, 0x00, 0x0a, 0xcc, 0xff, 0xfe, 0x00, 0x0a,
	0x00, 0x00, 0x00, 0x0d, 0x12, 0x08, 0x41, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x00, 0x03, 0xf7, 0xbf, 0x00, 0x0d,
	0xef, 0xff, 0x00, 0x06, 0xee, 0x0f, 0xe1, 0x00, 0x06,
	0xf0, 0x00, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0d, 0x45, 0xf7, 0xbf, 0x00, 0x0d,
	0xf7, 0xfe, 0x00, 0x06, 0xee, 0x07, 0xe2, 0x00, 0x06,
	0xff, 0xfe, 0x00, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x0b,
	0x00, 0x00, 0x00, 0x0d, 0x67, 0xf7, 0xbf, 0x00, 0x0d,
	0x00, 0x00, 0x00, 0x0d, 0x89, 0x00, 0x00, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x09, 0x01,
	0x00, 0x00, 0x10, 0x0d, 0xaa, 0x00, 0x00, 0x18, 0x0d,
	0x00, 0x00, 0x00, 0x0d, 0xbb, 0x10, 0x82, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00,
	0x08, 0x41, 0x00, 0x09, 0x44, 0x08, 0x61, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x0a, 0xcc, 0x20, 0x04, 0x00, 0x0d,
	0x00, 0x00, 0x00, 0x0a, 0xcd, 0xdf, 0xfc, 0x00, 0x0d,
	0x00, 0x00, 0x00, 0x0d, 0xee, 0xef, 0x7e, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0xe0, 0x01, 0x00,
	0xf7, 0xbf, 0x00, 0x09, 0x77, 0xf7, 0x9f, 0x00, 0x09,
	0x00, 0x00, 0x00, 0x0b, 0x0f, 0xdf, 0xfc, 0x00, 0x0d,
	0x00, 0x00, 0x00, 0x0b, 0x00, 0x20, 0x04, 0x00, 0x0e,
	0x00, 0x00, 0x01, 0x00, 0x01, 0x08, 0x41, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0x23, 0x00, 0x00, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0x44, 0x08, 0x41, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0x56, 0x00, 0x00, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0x77, 0x08, 0x41, 0x00, 0x0e,
	0x00, 0x00, 0x01, 0x00, 0x08, 0xf7, 0xbf, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0x9a, 0x00, 0x00, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0xbb, 0xf7, 0xbf, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0xcd, 0x00, 0x00, 0x00, 0x0e,
	0x00, 0x00, 0x00, 0x0e, 0xee, 0xf7, 0xbf, 0x00, 0x0e,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x09, 0x01,
	0x00, 0x00, 0x10, 0x0e, 0xff, 0x00, 0x00, 0x18, 0x0e,
	0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x01, 0x00, 0x02, 0x21, 0x04, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0a, 0xc3, 0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x01, 0x00, 0x05, 0xde, 0xfc, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0b, 0x07, 0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x41, 0x00, 0x0f,
	0x08, 0x00, 0x00, 0x0f, 0x9a, 0x0f, 0xff, 0x00, 0x0f,
	0xf8, 0x00, 0x00, 0x0f, 0xbc, 0xf0, 0x01, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0c, 0xfd, 0x10, 0x82, 0x00, 0x0f,
	0x00, 0x01, 0x00, 0x0f, 0xec, 0xf8, 0x02, 0x00, 0x0f,
	0xff, 0xff, 0x00, 0x0f, 0xfa, 0x07, 0xfe, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x0d, 0x10, 0x10, 0x82, 0x00, 0x10,
	0x00, 0x00, 0x01, 0x00, 0x01, 0xf7, 0xbf, 0x00, 0x10,
	0xf8, 0x00, 0x00, 0x0f, 0xb2, 0xf0, 0x01, 0x00, 0x10,
	0x08, 0x00, 0x00, 0x0f, 0x93, 0x0f, 0xff, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x0d, 0x44, 0xef, 0x7e, 0x00, 0x10,
	0xff, 0xff, 0x00, 0x0f, 0xf3, 0x07, 0xfe, 0x00, 0x10,
	0x00, 0x01, 0x00, 0x0f, 0xe2, 0xf8, 0x02, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x0d, 0x65, 0xef, 0x7e, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x10, 0x67, 0x00, 0x00, 0x00, 0x10,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x11, 0x01,
	0x00, 0x00, 0x20, 0x10, 0x88, 0x00, 0x00, 0x30, 0x10,
	0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10,
	0x20, 0x04, 0x00, 0x0a, 0xcc, 0x40, 0x08, 0x00, 0x0a,
	0xdf, 0xfc, 0x00, 0x0a, 0xcc, 0xbf, 0xf8, 0x00, 0x0a,
	0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10,
	0xdf, 0xfc, 0x00, 0x0b, 0x00, 0xbf, 0xf8, 0x00, 0x0b,
	0x20, 0x04, 0x00, 0x0b, 0x00, 0x40, 0x08, 0x00, 0x0b,
	0x00, 0x00, 0x01, 0x00, 0x0b, 0x08, 0x41, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x10, 0xcc, 0x08, 0x01, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x10, 0xdd, 0x08, 0x00, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x10, 0xee, 0xf7, 0xff, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x10, 0xff, 0x00, 0x01, 0x00, 0x10,
	0x00, 0x00, 0x00, 0x11, 0x00, 0x10, 0x82, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x11, 0x08, 0x01, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x22, 0xf7, 0xff, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x33, 0x10, 0x82, 0x00, 0x11,
	0x00, 0x00, 0x01, 0x00, 0x04, 0xf7, 0xbf, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x55, 0xf8, 0x00, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x66, 0xff, 0xff, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x77, 0xef, 0x7e, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0x88, 0xef, 0x7e, 0x00, 0x11,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x11, 0x01,
	0x00, 0x00, 0x20, 0x11, 0x99, 0x00, 0x00, 0x30, 0x11,
	0x00, 0x00, 0x00, 0x11, 0xab, 0x00, 0x00, 0x00, 0x11,
	0x21, 0x04, 0x01, 0x00, 0x00, 0x42, 0x08, 0x01, 0x00,
	0xde, 0xfc, 0x01, 0x00, 0x00, 0xbd, 0xf8, 0x01, 0x00,
	0x00, 0x00, 0x01, 0x00, 0x0c, 0x08, 0x41, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0xde, 0x10, 0x02, 0x00, 0x11,
	0x00, 0x00, 0x00, 0x11, 0xf0, 0x10, 0x00, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x12, 0x12, 0xef, 0xfe, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x12, 0x13, 0x00, 0x02, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x0c, 0xf4, 0x21, 0x04, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x12, 0x56, 0x10, 0x02, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x11, 0xf7, 0xef, 0xfe, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x0d, 0x18, 0x21, 0x04, 0x00, 0x12,
	0x00, 0x00, 0x01, 0x00, 0x09, 0xf7, 0xbf, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x12, 0x5a, 0xf0, 0x00, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x11, 0xdb, 0xff, 0xfe, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x0d, 0x4c, 0xde, 0xfc, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x0d, 0x6d, 0xde, 0xfc, 0x00, 0x12,
	0x00, 0x00, 0x00, 0x12, 0xef, 0x00, 0x00, 0x00, 0x12,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x21, 0x01,
	0x00, 0x00, 0x40, 0x13, 0x00, 0x00, 0x00, 0x60, 0x13,
	0x00, 0x00, 0x01, 0x00, 0x01, 0x08, 0x41, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x22, 0x08, 0x00, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x33, 0x10, 0x02, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x44, 0xff, 0xff, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x55, 0x10, 0x00, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x66, 0xf8, 0x00, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x77, 0xef, 0xfe, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x88, 0x00, 0x02, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0x99, 0x21, 0x04, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0xaa, 0x00, 0x01, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0xbb, 0x10, 0x02, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0xcc, 0xef, 0xfe, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0xdd, 0x21, 0x04, 0x00, 0x13,
	0x00, 0x00, 0x01, 0x00, 0x0e, 0xf7, 0xbf, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x13, 0xff, 0xf0, 0x00, 0x00, 0x13,
	0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0xfe, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x14, 0x11, 0xde, 0xfc, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x14, 0x22, 0xde, 0xfc, 0x00, 0x14,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x21, 0x01,
	0x00, 0x00, 0x40, 0x14, 0x33, 0x00, 0x00, 0x60, 0x14,
	0x00, 0x00, 0x01, 0x01, 0x22, 0x00, 0x00, 0x41, 0x01,
	0x00, 0x00, 0x01, 0x00, 0x04, 0x08, 0x41, 0x00, 0x14,
	0x00, 0x00, 0x01, 0x00, 0x05, 0x10, 0x00, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x11, 0xd6, 0x20, 0x04, 0x00, 0x14,
	0x00, 0x00, 0x01, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x11, 0xf8, 0x20, 0x00, 0x00, 0x14,
	0x00, 0x00, 0x01, 0x00, 0x09, 0xf0, 0x00, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x12, 0x1a, 0xdf, 0xfc, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x12, 0x1b, 0x00, 0x04, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x0c, 0xfc, 0x42, 0x08, 0x00, 0x14,
	0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x12, 0x5e, 0x20, 0x04, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x11, 0xff, 0xdf, 0xfc, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x0d, 0x10, 0x42, 0x08, 0x00, 0x15,
	0x00, 0x00, 0x01, 0x00, 0x01, 0xf7, 0xbf, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x12, 0x52, 0xe0, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x11, 0xd3, 0xff, 0xfc, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x0d, 0x44, 0xbd, 0xf8, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x0d, 0x65, 0xbd, 0xf8, 0x00, 0x15,
	0x00, 0x00, 0x01, 0x01, 0xcc, 0x00, 0x00, 0x41, 0x01,
	0x00, 0x00, 0x01, 0x00, 0x06, 0x08, 0x41, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x15, 0x77, 0x10, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x11, 0xd8, 0x00, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x15, 0x99, 0xff, 0xfe, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x11, 0xfa, 0x00, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x15, 0xbb, 0xf0, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x12, 0x1d, 0x00, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x0c, 0xfe, 0x00, 0x00, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x15, 0xff, 0x00, 0x02, 0x00, 0x15,
	0x00, 0x00, 0x00, 0x12, 0x50, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x11, 0xf1, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x0d, 0x12, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x01, 0x00, 0x03, 0xf7, 0xbf, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x12, 0x54, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x11, 0xd5, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x0d, 0x46, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x00, 0x0d, 0x67, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x41, 0x00, 0x16,
	0x00, 0x00, 0x01, 0x00, 0x09, 0x20, 0x00, 0x00, 0x16,
	0x20, 0x04, 0x00, 0x11, 0xdd, 0x40, 0x08, 0x00, 0x11,
	0x00, 0x00, 0x01, 0x00, 0x0a, 0xff, 0xfc, 0x00, 0x16,
	0x20, 0x00, 0x00, 0x11, 0xff, 0x40, 0x00, 0x00, 0x11,
	0x00, 0x00, 0x01, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x16,
	0xdf, 0xfc, 0x00, 0x12, 0x11, 0xbf, 0xf8, 0x00, 0x12,
	0x00, 0x04, 0x00, 0x12, 0x11, 0x00, 0x08, 0x00, 0x12,
	0x42, 0x08, 0x00, 0x0c, 0xff, 0x83, 0xf0, 0x00, 0x0c,
	0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x16,
	0x20, 0x04, 0x00, 0x12, 0x55, 0x40, 0x08, 0x00, 0x12,
	0xdf, 0xfc, 0x00, 0x11, 0xff, 0xbf, 0xf8, 0x00, 0x11,
	0x42, 0x08, 0x00, 0x0d, 0x11, 0x83, 0xf1, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x00, 0x0d, 0xf7, 0xbf, 0x00, 0x16,
	0xe0, 0x00, 0x00, 0x12, 0x55, 0xc0, 0x00, 0x00, 0x12,
	0xff, 0xfc, 0x00, 0x11, 0xdd, 0xff, 0xf8, 0x00, 0x11,
	0xbd, 0xf8, 0x00, 0x0d, 0x44, 0x7b, 0xf0, 0x00, 0x0d,
	0xbd, 0xf8, 0x00, 0x0d, 0x66, 0x74, 0x0f, 0x00, 0x0d,
	0x00, 0x00, 0x01, 0x00, 0x0e, 0x08, 0x41, 0x00, 0x16,
	0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x16,
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x03, 0xf7, 0xbf, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x04, 0x08, 0x41, 0x00, 0x17,
	0x20, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00,
	0xff, 0xfc, 0x01, 0x00, 0x00, 0xff, 0xf8, 0x01, 0x00,
	0xe0, 0x00, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x01, 0x00,
	0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
	0x00, 0x00, 0x01, 0x00, 0x05, 0xf7, 0xbf, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x06, 0x08, 0x41, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x07, 0xf7, 0xbf, 0x00, 0x17,
	0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x41, 0x01, 0x00,
	0x00, 0x00, 0x01, 0x00, 0x00, 0xf7, 0xbf, 0x01, 0x00,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f,
	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f
};

void dl_init( usb_dev_handle* handle ) {

	uint8_t edid[128];
	uint8_t peek;

	dl_cmdstream cs;
	create( &cs, 10*1024 );

	printf("dl_init(): starting DisplayLink initialization..\n");

	// windows driver does this about once a second:
	// f0005000 seems to be default response
	// f0002000 sometimes seen when device is messed up
	int poll = dl_poll( handle );
	printf( "  dl_poll() = 0x%08x\n", poll );

	// always seems to return 0x82
	peek = dl_peek( 0xC484, handle );
	printf( "  dl_peek(0xC484) = 0x%02hhx\n", peek );

	// original driver does this, but no visible effect
	printf( "  dl_poke(0xC41F,0x01)\n" );
	dl_poke( 0xC41F, 0x01, handle );

	dl_get_edid( edid, handle );
	printf( "  EDID data:\n" );
	for (int i = 0; i < 8; i++) {
		printf( "    " );
		for (int j = 0; j < 16; j++) printf( "%02hhx ", edid[i*16+j] );
		printf( "\n" );
	}

	printf( "  setting decryption null-key..\n" );
	dl_set_key( nullkey1, handle );

	// original driver does this, but no visible effect
	printf( "  dl_poke(0xC40B,0x00)\n" );
	dl_poke( 0xC40B, 0x00, handle );

	printf( "  sending decompressor table (%d bytes)..\n", sizeof(dl_decomp_table) );
	dl_decomp_table_command( &cs, sizeof(dl_decomp_table), dl_decomp_table );
	send( &cs, handle );

	printf("dl_init(): initialization done.\n\n");
	destroy( &cs );
}

void dl_dumpmem( usb_dev_handle* handle, char* f ) {
	FILE* dump = fopen(f,"w+");
	for (int base = 0; base < 0x100; base++) {
		fprintf(dump,"  register space @ 0x%04x:\n", base<<8 );
		for (int i = 0; i < 256; i++ ) {
			if (i % 16 == 0) fprintf(dump,"    ");
			uint8_t peek = dl_peek( (base<<8)+i, handle );
			fprintf(dump,"%02hhx ",peek);
			if (i % 16 == 15) fprintf(dump,"\n");
		}
	}
	fclose(dump);
}

/******************* HELPER FUNCTIONS *********************/

usb_dev_handle* usb_get_device_handle( int vendor, int product, int interface = 0 ) {

	usb_init();
	usb_find_busses();
	usb_find_devices();

	struct usb_bus* busses = usb_get_busses();

	for ( struct usb_bus* bus = busses; bus; bus = bus->next ) {
		for ( struct usb_device* dev = bus->devices; dev; dev = dev->next ) {
			if ((dev->descriptor.idVendor == vendor) && (dev->descriptor.idProduct == product)) {
				usb_dev_handle* handle = usb_open(dev);
				if (!handle) return 0;
				if (usb_claim_interface(handle,0) < 0) return 0;
				return handle;
			}
		}
	}
	return 0;
}

void rgb24_to_rgb16( uint8_t* rgb24, uint8_t* rgb16, int count ) {
	for (int i = 0; i < count; i++) {
		uint8_t r = rgb24[i*3+0];
		uint8_t g = rgb24[i*3+1];
		uint8_t b = rgb24[i*3+2];
		rgb16[i*2+0] =  (r & 0xF8)       | ((g & 0xE0) >> 5);
		rgb16[i*2+1] = ((g & 0x1C) << 3) | ((b & 0xF8) >> 3);
	}
}


void read_rgb24( const char* filename, uint8_t* rgb24, int count ) {
	int f = open(filename,O_RDONLY);
	read( f, rgb24, count*3 );
	close(f);
}

uint8_t* read_rgb16( const char* filename, int count ) {

	uint8_t* rgb16 = (uint8_t*)malloc(count*2);
	uint8_t* rgb24 = (uint8_t*)malloc(count*3);

	read_rgb24(filename,rgb24,count);
	rgb24_to_rgb16(rgb24,rgb16,count);

	free( rgb24 );
	return rgb16;
}


/******************* MAIN ROUTINE *************************/

int main(int argc, char* argv[] ) {

	printf("\ndisplaylink userspace controller demo 0.0.1\n\n");
	printf("written 2008/09 by floe at butterbrot.org\n");
	printf("in cooperation with chrisly at platon42.de\n");
 	printf("this code is released as public domain.\n\n");
	printf("this is so experimental that the warranty shot itself.\n");
	printf("so don't expect any.\n\n");
	printf("(note: you can pass a 640x960 pixel RGB raw image file as parameter)\n\n");

//	#define XRES 640
	#define XRES 800
	#define YRES 480

	dl_cmdstream cs;
	create( &cs, 1024*1024 );

//	usb_dev_handle* handle = usb_get_device_handle( 0x17E9, 0x01AE );
	usb_dev_handle* handle = usb_get_device_handle( 0x17E9, 0x0103 );
	if (!handle) {
		printf("!handle\n\n");
		return 1;
	}

	// startup control messages & firmware
	dl_init( handle );

	// default register set & offsets
	printf("setting default registers for 800x480..\n");
	dl_set_registers( &cs, dl_register_init_U70 );
	dl_set_offsets( &cs, 0x000000, 0x000A00, 0x555555, 0x000500 );
	/*dl_set_offsets( &cs, 0x000000, 0x000A00, 0x555555, 0x000500 );
	dl_unknown_command( &cs );
	dl_set_offsets( &cs, 0x000000, 0x000A00, 0x555555, 0x000500 );*/
	dl_set_register( &cs, DL_REG_BLANK_SCREEN, 0x00 ); // enable output
	dl_set_register( &cs, DL_REG_SYNC, 0xFF );
	dl_sync_command( &cs );
	send( &cs, handle );

	sleep(1);

	//dl_dumpmem(handle,"dump1.log");

	// fill with a bunch of red
	printf("filling screen with red gradient..\n");
	rle_word red = { 0x00, 0x0000 };
	for (int i = 0; i < YRES; i++) {
		dl_gfx_rle( &cs, i*XRES*2,      0x00, &red );
		dl_gfx_rle( &cs, i*XRES*2+512,  0x00, &red );
		dl_gfx_rle( &cs, i*XRES*2+1024, 0x00, &red );
		red.value = (i/15) << 11;
	}
	dl_sync_command( &cs );
	send( &cs, handle );

	sleep(1);

	// grr. I'm pretty sure that I'm right about the stride register,
	// but I can't get it to have any effect...
	/*dl_set_register( &cs, DL_REG_SYNC, 0x00 );
	dl_set_address(  &cs, DL_ADDR_FB16_STRIDE, X*2 );
	dl_set_address(  &cs, DL_ADDR_FB8_STRIDE, X );
	dl_set_register( &cs, DL_REG_SYNC, 0xFF );
	dl_sync_command( &cs );
	send( &cs, handle );*/

	if (argc >= 2) {

		// fill with an image
		printf("filling screen with an image..\n");
//		#define X 640
                #define X 800
		#define Y 960

		uint8_t* image = read_rgb16(argv[1],X*Y);
		for (int i = 0; i < (X*Y)/256; i++) {
			dl_gfx_write( &cs, i*256*2, 0x00, image+(i*256*2) );
			if ((i % 100) == 0) {
				dl_sync_command( &cs );
				send( &cs, handle );
			}
		}
		dl_sync_command( &cs );
		send( &cs, handle );

		sleep(1);
	}

	// some vertical scrolling
	printf("doing vertical scrolling (why doesn't horizontal work?)..\n");
	for (int i = 0; i < YRES; i++) {
		dl_set_register( &cs, DL_REG_SYNC, 0x00 );
		dl_set_address(  &cs, DL_ADDR_FB16_START, i*XRES*2 );
		dl_set_register( &cs, DL_REG_SYNC, 0xFF );
		dl_sync_command( &cs );
		send( &cs, handle );
		usleep(5000);
	}

	//dl_dumpmem(handle,"dump2.log");

	sleep(1);

	// some memcopy
	printf("doing bitblt..\n\n");
	dl_set_offsets( &cs, 0x000000, 0x000A00, 0x555555, 0x000500 );
	for (int i = 0; i < 100; i++) {
		dl_gfx_copy( &cs, 0x500*(280+i)+320*2, 0x500*(380+i)+420*2, 100 );
	}
	dl_sync_command( &cs );
	send( &cs, handle );

	printf("goodbye.\n\n");
	usb_close( handle );
	destroy( &cs );
}


