/*
 * sixaxis-init
 *
 * build:
 *   gcc -lusb -o sixaxis-init sixaxis-init.c
 *   (require libusb 0.1.12 SDK)
 */

#include <usb.h>
#include <stdio.h>

#define SIXAXIS_VENDOR_ID       0x054c
#define SIXAXIS_PRODUCT_ID      0x0268
#define SIXAXIS_SPECIAL_REQUEST ((0x03 << 8) | 0xf2)

#define USB_DIR_IN              0x80
#define HID_REQ_GET_REPORT      0x01
#define USB_CTRL_GET_TIMEOUT    5000

int verbose = 1;        // DEFAULT: verbose mode


void printDevice(struct usb_device *dev) 
{
  usb_dev_handle *udev;
  char strVendor[256];
  char strProduct[256];

  printf("%s (0x%08x) : %s\n", 
         dev->bus->dirname, dev->bus->location, dev->filename);
  
  if (!(udev = usb_open(dev)))
    return;

  if (dev->descriptor.iManufacturer &&
      dev->descriptor.iProduct &&
      usb_get_string_simple(udev, dev->descriptor.iManufacturer, 
                            strVendor, sizeof(strVendor)) > 0 &&
      usb_get_string_simple(udev, dev->descriptor.iProduct, 
                            strProduct, sizeof(strProduct)) > 0) {
    printf("  %s - %s\n", strVendor, strProduct);
  }

  usb_close(udev);
}


int initSIXAXIS(struct usb_device *dev)
{
  usb_dev_handle *udev;
  int   ifnum, ret, i;
  char  buf[17];

  ifnum = dev->config->interface->altsetting->bInterfaceNumber;

  if (!(udev = usb_open(dev)))
    return -1;

  // usb_set_configuration(udev, dev->config->bConfigurationValue);
  // usb_claim_interface(udev, ifnum);
  
  if (verbose)
    printf("    REQUEST: Get_Report >> 0x%04x\n", SIXAXIS_SPECIAL_REQUEST);
  
  ret = usb_control_msg(udev,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                        HID_REQ_GET_REPORT,
                        SIXAXIS_SPECIAL_REQUEST,
                        ifnum, 
                        buf,
                        17,
                        USB_CTRL_GET_TIMEOUT);

  // usb_release_interface(udev, ifnum);
  
  usb_close(udev);

  if (ret < 0) {
    if (verbose)
      printf("    ERROR: SIXAXIS not responsed\n");
    return -1;
  }
  
  if (verbose) {
    printf("    SUCCESS: Data <<");
    for (i = 0; i < 17; i++) {
      printf(" %02x", buf[i] & 0xff);
    }
    printf("\n");
  }

  return 0;
}


int main(int argc, char *argv[]) 
{
  struct usb_bus *bus;
  struct usb_device *dev;
  int sixaxis_num = 0;
  int sixaxis_init_error = 0;

  if (argc > 1 && !strcmp(argv[1], "-q"))
    verbose = 0;
  if (argc > 1 && !strcmp(argv[1], "-v"))
    verbose = 1;

  // usb_set_debug(5);

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

  for (bus = usb_get_busses(); bus; bus = bus->next) {
    for (dev = bus->devices; dev; dev = dev->next) {
      if (verbose)
        printDevice(dev);
      if (dev->descriptor.idVendor  == SIXAXIS_VENDOR_ID &&
          dev->descriptor.idProduct == SIXAXIS_PRODUCT_ID) {
        sixaxis_num++;
        if (initSIXAXIS(dev) < 0)
          sixaxis_init_error++;
      }
    }
  }

  if (verbose && sixaxis_num == 0)
    printf("ERROR: SIXAXIS not found\n");

  if (sixaxis_num == 0 || sixaxis_init_error > 0)
    return -1;

  if (verbose)
    printf("SIXAXIS initialized\n");
  
  return 0;
}

