// File: DavieV[P]virtual-usb-printer/main.cc
// Function: main
int main() {
  const USB_DEVICE_DESCRIPTOR device = {
      0x12,                   // Size of this descriptor in bytes
      USB_DESCRIPTOR_DEVICE,  // descriptor type
      0x0110,                 // USB Spec Release Number in BCD format
      0x00,                   // Class Code
      0x00,                   // Subclass code
      0x00,                   // Protocol code
      0x08,                   // Max packet size for EP0, see usb_config.h
      0x04a9,                 // Vendor ID
      0x27e8,                 // Product ID
      0x0000,                 // Device release number in BCD format
      0x01,                   // Manufacturer string descriptor index
      0x02,                   // Product string descriptor index
      0x01,                   // Device serial number string descriptor index
      0x01,                   // Number of possible configurations
  };

  const USB_CONFIGURATION_DESCRIPTOR configuration = {
      0x09,                          // Size of this descriptor in bytes.
      USB_DESCRIPTOR_CONFIGURATION,  // descriptor type.
      0x20,  // Total length of data for this configuration.
      0x01,  // Number of interfaces in this configuration.
      0x01,  // Index value for this configuration.
      0x00,  // Configuration string descriptor index.
      0x80,  // Configuration characteristics (bmAttributes).
      0x00,  // Max power consumption (2X mA).
  };

  std::vector<char> str1 = {
      0x04, USB_DESCRIPTOR_STRING, // bLength, bDscType
      0x09, 0x04
  };

  std::vector<char> str2 = {
      0x0E, USB_DESCRIPTOR_STRING, // bLength, bDscType
      'D', 0x00,
      'a', 0x00,
      'v', 0x00,
      'i', 0x00,
      'e', 0x00,
      'V', 0x00,
  };

  std::vector<char> str3 = {
      0x28, USB_DESCRIPTOR_STRING, // bLength, bDscType
      'V', 0x00,
      'i', 0x00,
      'r', 0x00,
      't', 0x00,
      'u', 0x00,
      'a', 0x00,
      'l', 0x00,
      ' ', 0x00,
      'U', 0x00,
      'S', 0x00,
      'B', 0x00,
      ' ', 0x00,
      'P', 0x00,
      'r', 0x00,
      'i', 0x00,
      'n', 0x00,
      't', 0x00,
      'e', 0x00,
      'r', 0x00,
  };

  const std::vector<std::vector<char>> strings = {str1, str2, str3};

  const std::vector<char> ieee_device_id = {
    0x00, 0x1A,  // Length (26 bytes)
    'M', 'F', 'G', ':', 'D', 'V', '3', ';',
    'C', 'M', 'D', ':', 'P', 'D', 'F', ';',
    'M', 'D', 'L', ':', 'V', 'T', 'L', ';',
  };

  const std::vector<USB_INTERFACE_DESCRIPTOR> interfaces = {
      {
          0x09,                      // Size of this descriptor in bytes
          USB_DESCRIPTOR_INTERFACE,  // descriptor type.
          0x00,                      // Interface Number.
          0x00,                      // Alternate Setting Number.
          0x02,                      // Number of endpoints in this interface.
          0x07,                      // Class code.
          0x01,                      // Subclass code.
          0x02,                      // Protocol code.
          0x00,                      // Interface string index.
      },
      /*
      {
          0x09,                      // Size of this descriptor in bytes
          USB_DESCRIPTOR_INTERFACE,  // descriptor type.
          0x01,                      // Interface Number.
          0x00,                      // Alternate Setting Number.
          0x02,                      // Number of endpoints in this interface.
          0x07,                      // Class code.
          0x01,                      // Subclass code.
          0x02,                      // Protocol code.
          0x00,                      // Interface string index.
      }*/};

  const std::vector<USB_ENDPOINT_DESCRIPTOR> endpoints = {
      {
          0x07,                     // Size of this descriptor in bytes.
          USB_DESCRIPTOR_ENDPOINT,  // descriptor type.
          0x01,                     // Endpoint Address.
          0x02,                     // Attributes (Bulk Endpoint).
          512,                      // Max transfer size.
          0x00,                     // Interval.
      },
      {
          0x07,                     // Size of this descriptor in bytes.
          USB_DESCRIPTOR_ENDPOINT,  // descriptor type.
          0x81,                     // Endpoint Address.
          0x02,                     // Attributes (Bulk Endpoint).
          512,                      // Max transfer size.
          0x00,                     // Interval.
      },
      /*
      {
          0x07,                     // Size of this descriptor in bytes.
          USB_DESCRIPTOR_ENDPOINT,  // descriptor type.
          0x03,                     // Endpoint Address.
          0x02,                     // Attributes (Bulk Endpoint).
          0x08,                     // Max transfer size.
          0x00,                     // Interval.
      },
      {
          0x07,                     // Size of this descriptor in bytes.
          USB_DESCRIPTOR_ENDPOINT,  // descriptor type.
          0x84,                     // Endpoint Address.
          0x02,                     // Attributes (Bulk Endpoint).
          0x08,                     // Max transfer size.
          0x00,                     // Interval.
      }*/};

  UsbPrinter printer(device, configuration, strings, ieee_device_id, interfaces,
                     endpoints);
  run_server(printer);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3e0, %rsp            # imm = 0x3E0
movl $0x0, -0x4(%rbp)
movups 0x2d8f(%rip), %xmm0     # 0x9518
movaps %xmm0, -0x20(%rbp)
movw $0x101, -0x10(%rbp)     # imm = 0x101
movabsq $-0x7ffffefeffdffdf7, %rax # imm = 0x8000010100200209
movq %rax, -0x30(%rbp)
movb $0x0, -0x28(%rbp)
movb $0x4, -0x5c(%rbp)
movb $0x3, -0x5b(%rbp)
movb $0x9, -0x5a(%rbp)
movb $0x4, -0x59(%rbp)
leaq -0x5c(%rbp), %rax
movq %rax, -0x58(%rbp)
movq $0x4, -0x50(%rbp)
leaq -0x5d(%rbp), %rdi
movq %rdi, -0x368(%rbp)
callq 0x2280
movq -0x368(%rbp), %rcx
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
leaq -0x48(%rbp), %rdi
callq 0x6f10
jmp 0x67ef
leaq -0x5d(%rbp), %rdi
callq 0x21c0
movb $0xe, -0xa6(%rbp)
movb $0x3, -0xa5(%rbp)
movb $0x44, -0xa4(%rbp)
movb $0x0, -0xa3(%rbp)
movb $0x61, -0xa2(%rbp)
movb $0x0, -0xa1(%rbp)
movb $0x76, -0xa0(%rbp)
movb $0x0, -0x9f(%rbp)
movb $0x69, -0x9e(%rbp)
movb $0x0, -0x9d(%rbp)
movb $0x65, -0x9c(%rbp)
movb $0x0, -0x9b(%rbp)
movb $0x56, -0x9a(%rbp)
movb $0x0, -0x99(%rbp)
leaq -0xa6(%rbp), %rax
movq %rax, -0x98(%rbp)
movq $0xe, -0x90(%rbp)
leaq -0xa7(%rbp), %rdi
movq %rdi, -0x370(%rbp)
callq 0x2280
movq -0x370(%rbp), %rcx
movq -0x98(%rbp), %rsi
movq -0x90(%rbp), %rdx
leaq -0x88(%rbp), %rdi
callq 0x6f10
jmp 0x68a9
leaq -0xa7(%rbp), %rdi
callq 0x21c0
movabsq $0x7200650074006e, %rax # imm = 0x7200650074006E
movq %rax, -0xe0(%rbp)
movups 0x2c76(%rip), %xmm0     # 0x9543
movaps %xmm0, -0xf0(%rbp)
movups 0x2c58(%rip), %xmm0     # 0x9533
movaps %xmm0, -0x100(%rbp)
leaq -0x100(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq $0x28, -0xc8(%rbp)
leaq -0x101(%rbp), %rdi
movq %rdi, -0x378(%rbp)
callq 0x2280
movq -0x378(%rbp), %rcx
movq -0xd0(%rbp), %rsi
movq -0xc8(%rbp), %rdx
leaq -0xc0(%rbp), %rdi
callq 0x6f10
jmp 0x6931
leaq -0x101(%rbp), %rdi
callq 0x21c0
leaq -0x178(%rbp), %rdi
movq %rdi, -0x180(%rbp)
leaq -0x48(%rbp), %rsi
callq 0x4530
jmp 0x6956
leaq -0x160(%rbp), %rdi
movq %rdi, -0x180(%rbp)
leaq -0x88(%rbp), %rsi
callq 0x4530
jmp 0x6972
leaq -0x148(%rbp), %rdi
movq %rdi, -0x180(%rbp)
leaq -0xc0(%rbp), %rsi
callq 0x4530
jmp 0x698e
leaq -0x178(%rbp), %rax
movq %rax, -0x130(%rbp)
movq $0x3, -0x128(%rbp)
leaq -0x181(%rbp), %rdi
movq %rdi, -0x380(%rbp)
callq 0x6f90
movq -0x380(%rbp), %rcx
movq -0x130(%rbp), %rsi
movq -0x128(%rbp), %rdx
leaq -0x120(%rbp), %rdi
callq 0x6fb0
jmp 0x69dd
leaq -0x181(%rbp), %rdi
callq 0x4a50
leaq -0x178(%rbp), %rax
movq %rax, -0x390(%rbp)
addq $0x48, %rax
movq %rax, -0x388(%rbp)
movq -0x388(%rbp), %rdi
addq $-0x18, %rdi
movq %rdi, -0x398(%rbp)
callq 0x4710
movq -0x390(%rbp), %rcx
movq -0x398(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x388(%rbp)
jne 0x6a02
movups 0x2b2b(%rip), %xmm0     # 0x9565
movups %xmm0, -0x1c6(%rbp)
movups 0x2b13(%rip), %xmm0     # 0x955b
movaps %xmm0, -0x1d0(%rbp)
leaq -0x1d0(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movq $0x1a, -0x1a8(%rbp)
leaq -0x1d1(%rbp), %rdi
movq %rdi, -0x3a0(%rbp)
callq 0x2280
movq -0x3a0(%rbp), %rcx
movq -0x1b0(%rbp), %rsi
movq -0x1a8(%rbp), %rdx
leaq -0x1a0(%rbp), %rdi
callq 0x6f10
jmp 0x6a9e
leaq -0x1d1(%rbp), %rdi
callq 0x21c0
movb $0x9, -0x209(%rbp)
movb $0x4, -0x208(%rbp)
movb $0x0, -0x207(%rbp)
movb $0x0, -0x206(%rbp)
movb $0x2, -0x205(%rbp)
movb $0x7, -0x204(%rbp)
movb $0x1, -0x203(%rbp)
movb $0x2, -0x202(%rbp)
movb $0x0, -0x201(%rbp)
leaq -0x209(%rbp), %rax
movq %rax, -0x200(%rbp)
movq $0x1, -0x1f8(%rbp)
leaq -0x20a(%rbp), %rdi
movq %rdi, -0x3a8(%rbp)
callq 0x7030
movq -0x3a8(%rbp), %rcx
movq -0x200(%rbp), %rsi
movq -0x1f8(%rbp), %rdx
leaq -0x1f0(%rbp), %rdi
callq 0x7050
jmp 0x6b38
leaq -0x20a(%rbp), %rdi
callq 0x3220
movb $0x7, -0x246(%rbp)
movb $0x5, -0x245(%rbp)
movb $0x1, -0x244(%rbp)
movb $0x2, -0x243(%rbp)
movw $0x200, -0x242(%rbp)    # imm = 0x200
movb $0x0, -0x240(%rbp)
movb $0x7, -0x23f(%rbp)
movb $0x5, -0x23e(%rbp)
movb $-0x7f, -0x23d(%rbp)
movb $0x2, -0x23c(%rbp)
movw $0x200, -0x23b(%rbp)    # imm = 0x200
movb $0x0, -0x239(%rbp)
leaq -0x246(%rbp), %rax
movq %rax, -0x238(%rbp)
movq $0x2, -0x230(%rbp)
leaq -0x247(%rbp), %rdi
movq %rdi, -0x3b0(%rbp)
callq 0x70d0
movq -0x3b0(%rbp), %rcx
movq -0x238(%rbp), %rsi
movq -0x230(%rbp), %rdx
leaq -0x228(%rbp), %rdi
callq 0x70f0
jmp 0x6beb
leaq -0x247(%rbp), %rdi
callq 0x51b0
leaq -0x2e0(%rbp), %rdi
leaq -0x1a0(%rbp), %rsi
callq 0x4530
jmp 0x6c0c
movq %rsp, %rax
leaq -0x228(%rbp), %rcx
movq %rcx, (%rax)
leaq -0x2c8(%rbp), %rdi
leaq -0x20(%rbp), %rsi
leaq -0x30(%rbp), %rdx
leaq -0x120(%rbp), %rcx
leaq -0x2e0(%rbp), %r8
leaq -0x1f0(%rbp), %r9
callq 0x3960
jmp 0x6c44
leaq -0x2e0(%rbp), %rdi
callq 0x4710
leaq -0x360(%rbp), %rdi
leaq -0x2c8(%rbp), %rsi
callq 0x7170
jmp 0x6c65
leaq -0x360(%rbp), %rdi
callq 0x6500
jmp 0x6c73
leaq -0x360(%rbp), %rdi
callq 0x7250
leaq -0x2c8(%rbp), %rdi
callq 0x7250
leaq -0x228(%rbp), %rdi
callq 0x72a0
leaq -0x1f0(%rbp), %rdi
callq 0x3030
leaq -0x1a0(%rbp), %rdi
callq 0x4710
leaq -0x120(%rbp), %rdi
callq 0x4770
leaq -0xc0(%rbp), %rdi
callq 0x4710
leaq -0x88(%rbp), %rdi
callq 0x4710
leaq -0x48(%rbp), %rdi
callq 0x4710
movl -0x4(%rbp), %eax
addq $0x3e0, %rsp            # imm = 0x3E0
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x5d(%rbp), %rdi
callq 0x21c0
jmp 0x6efe
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xa7(%rbp), %rdi
callq 0x21c0
jmp 0x6ef5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x101(%rbp), %rdi
callq 0x21c0
jmp 0x6ee9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
movq -0x180(%rbp), %rax
leaq -0x178(%rbp), %rcx
cmpq %rax, %rcx
movq %rax, -0x3b8(%rbp)
je 0x6d93
movq -0x3b8(%rbp), %rdi
addq $-0x18, %rdi
movq %rdi, -0x3c0(%rbp)
callq 0x4710
movq -0x3c0(%rbp), %rax
leaq -0x178(%rbp), %rcx
cmpq %rcx, %rax
movq %rax, -0x3b8(%rbp)
jne 0x6d62
jmp 0x6edd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x181(%rbp), %rdi
callq 0x4a50
leaq -0x178(%rbp), %rax
movq %rax, -0x3d0(%rbp)
addq $0x48, %rax
movq %rax, -0x3c8(%rbp)
movq -0x3c8(%rbp), %rdi
addq $-0x18, %rdi
movq %rdi, -0x3d8(%rbp)
callq 0x4710
movq -0x3d0(%rbp), %rcx
movq -0x3d8(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x3c8(%rbp)
jne 0x6dc9
jmp 0x6edd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x1d1(%rbp), %rdi
callq 0x21c0
jmp 0x6ed1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x20a(%rbp), %rdi
callq 0x3220
jmp 0x6ec5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x247(%rbp), %rdi
callq 0x51b0
jmp 0x6eb9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x6ead
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x2e0(%rbp), %rdi
callq 0x4710
jmp 0x6ead
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x6ea1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x360(%rbp), %rdi
callq 0x7250
leaq -0x2c8(%rbp), %rdi
callq 0x7250
leaq -0x228(%rbp), %rdi
callq 0x72a0
leaq -0x1f0(%rbp), %rdi
callq 0x3030
leaq -0x1a0(%rbp), %rdi
callq 0x4710
leaq -0x120(%rbp), %rdi
callq 0x4770
leaq -0xc0(%rbp), %rdi
callq 0x4710
leaq -0x88(%rbp), %rdi
callq 0x4710
leaq -0x48(%rbp), %rdi
callq 0x4710
movq -0x68(%rbp), %rdi
callq 0x2270
nopw (%rax,%rax)