/*
  This program is provided AS IS. 
  Copyright (c) 2000 Noriaki Mitsunaga
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <err.h>
#include <ctype.h>
#include <errno.h>
#include <libusb.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>

#define DEBUG

#define USB_IO_OUT0 0x1
#define USB_IO_OUT1 0x2
#define USB_IO_IN0  0x3
#define USB_IO_IN1  0x4

void usb_io_out(int port, int data,
		int fno, u_char *buf, int len, hid_item_t *hi) {
  int i;
  char bf[BUFSIZ];
  int size;

  if (len<2)
    return;

  hid_set_data(buf, hi, port & 0xff);
  hid_set_data(buf+1, hi, data & 0xff);
  for (i=2; i<len; i++)
    hid_set_data(buf+i, hi, 0);

  write(fno, buf, len);

  printf("out: ");
  for(i=0; i<len; i++)
    printf("%x ", buf[i]);
  
  printf("got: ");
  size = read(fno, bf, BUFSIZ);
  for(i=0; i<size; i++)
    printf("%x ", bf[i] & 0xff);
  printf("\n");
}

int usb_io_in(int port, int fno,
	      u_char *sbuf, int slen, hid_item_t *shi,
	      u_char *rbuf, int rlen, hid_item_t *rhi) {
  int i, pos;
  u_char buf[BUFSIZ];
  char bf[BUFSIZ];
  int size;

  if (slen<2)
    return -1;

  /* flush buffer */
 /* read(fno, buf, BUFSIZ); */

  hid_set_data(sbuf, shi, port & 0xff);
  for (i=1; i<slen; i++)
    hid_set_data(sbuf+i, shi, 0);

  write(fno, sbuf, slen);

  /* read(fno, rbuf, rlen); */
  printf("out: ");
  for(i=0; i<slen; i++)
    printf("%x ", sbuf[i]);
  
  printf("got: ");
  size = read(fno, bf, BUFSIZ);
  for(i=0; i<size; i++) {
    if(i<rlen)
      rbuf[i] = bf[i];
    printf("%x ", bf[i] & 0xff);
  }
  printf("\n");
  
  if ((hid_get_data(rbuf, rhi) & 0xff) != port) {
    fprintf(stderr, "err %x %x\n", rbuf[0], rbuf[1]);
    return(-2);
  }
  
  return(hid_get_data(rbuf+1, rhi) & 0xff);
}

int main(int argc, char **argv)
{
  FILE *fp;
  int fno, i;
  report_desc_t r;
  char devname[100], *dev = 0;
  int ch;
  int repdump = 0;
  int loop = 0;
  char *table = 0;
  hid_data_t hd;
  hid_item_t shi, rhi;
  int slen, rlen;
  char buf[BUFSIZ];
  u_char *sbuf, *rbuf;
  int pos;
  
  hid_init(NULL);
  
  if((fno = open("/dev/uhid0", O_RDWR)) < 0) {
    perror(argv[0]);
  }
  
  /* read header */
  r = hid_get_report_desc(fno);
  if (r == 0) 
    errx(1, "USB_GET_REPORT_DESC");
  
  /* parse */
  for (hd = hid_start_parse(r, 1<<hid_output);
       hid_get_item(hd, &shi); ) {
    if(shi.kind == hid_output)
      break;
  }
  hid_end_parse(hd);
  
  for (hd = hid_start_parse(r, 1<<hid_input);
       hid_get_item(hd, &rhi); ) {
    if(rhi.kind == hid_input)
      break;
  }
  hid_end_parse(hd);
  
  /* clear file inputs */
  read(fno, buf, BUFSIZ);
  
  /* prepare buffers */
  slen = hid_report_size(r, hid_output, 0);
  sbuf = malloc(slen);
  
  rlen = hid_report_size(r, hid_input, 0);
  rbuf = malloc(rlen);
  
  printf("port 0: %d\n", 
	 usb_io_in(USB_IO_IN0, fno, sbuf, slen, &shi, rbuf, rlen, &rhi));
  
  usb_io_out(USB_IO_OUT0, 0x55, fno, sbuf, slen, &shi);
  /* usb_io_out(USB_IO_OUT0, 0x55, fno, sbuf, slen, &shi); */
  
  printf("port 0: %d\n", 
	 usb_io_in(USB_IO_IN0, fno, sbuf, slen, &shi, rbuf, rlen, &rhi));
  printf("port 1: %d\n", 
	 usb_io_in(USB_IO_IN1, fno, sbuf, slen, &shi, rbuf, rlen, &rhi));
  
  free(sbuf);
  free(rbuf);
  hid_dispose_report_desc(r);
  
  close(fno);
  
  exit(0);
}
