Re: uinput oopses and bugs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



HI

I understand!

The device I tried to support was a USB Skype@phone EX-B
so I attempted to write a libusb uinput driver which I'm attaching
here for reference. I got up to working keypad, LED and ringer
without LCD or keypad and LCD without LED and ringer due to
EV_FF issue.

but now I got rid of this EX-B and obtained Yealink P1K that
already has driver in kernel, keyboard led ringer and display
all supported out of the box

If you can take some time, it would be maybe most useful to
look about what makes LED and SND being disabled by
EV_FF (no matter CUSTOM, SINE or any other type of effect)

Best regards, Davor
/* LICENSE=GPL */

/* iFeel force feedback uinput driver
** written by emard@xxxxxxxxxxxx
*/

/* compile with libusb, use gcc -lusb -lpthread */
#define THREAD 0

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#if THREAD
#include <pthread.h>
#endif
#include <signal.h>
#include <asm/types.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <usb.h>
#include <hid.h>

#if THREAD
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
#endif

#include "usbid.h"

#define TIMEOUT 3000
#define WAITINBETWEEN 500000

/* From HID specification */
#define SET_REQUEST 0x21
#define SET_REPORT 0x09 
#define OUTPUT_REPORT_TYPE 0x02

/* how many controlling threads */
#define THREADS 3

#define HAVEFF 0
int ledcounter = 0; /* debugging purpose */
#define MUTEX 0

char led0[] = { 
0x01,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
};

char led1[] = { 
0x01,0x11,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
};

char ring0[] = {
0x01,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};

char ring1[] = {
0x01,0xff,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};

struct lcdpacket {
  unsigned char type;
  unsigned char unknown[16];
  unsigned char bitmap[16];
};

#define SCANMAX 32
/* keys */
int keys[][2] = {
  { KEY_BACKSPACE, 0x01},
  { KEY_ENTER, 0x07 },
  { KEY_UP, 0x0d },
  { KEY_DOWN, 0x13 },
  { KEY_1, 0x04 },
  { KEY_2, 0x03 },
  { KEY_3, 0x02 },
  { KEY_4, 0x0a },
  { KEY_5, 0x09 },
  { KEY_6, 0x08 },
  { KEY_7, 0x10 },
  { KEY_8, 0x0f },
  { KEY_9, 0x0e },
  { KEY_KPASTERISK, 0x16 },
  { KEY_0, 0x15 },
  { KEY_KPPLUS, 0x14 },
  { KEY_MAX, 0 }
};

int scan2code[SCANMAX];

unsigned short usb_phone_vendor = USB_MOUSE_VENDOR;
unsigned short usb_phone_product = USB_MOUSE_PRODUCT;

#if THREAD
int rc[THREADS];
pthread_t thread[THREADS];
#endif

/* Global list of FDs each object is interested in,
** and FDs that there have been activity on. Each object
** adds itself to the fd_request_* lists on creation and removes
** itself on deletion, and checks the fd_* lists on poll.
*/
static fd_set fd_request_read, fd_request_write, fd_request_except;
static fd_set fd_read, fd_write, fd_except;
int fd_count = 0;

struct handset {
  struct usb_device *dev; /* libusb dev */
  struct usb_dev_handle *handle;
  int uifd; /* os-side uinput fd (read/write) */
  struct uinput_user_dev device;
  unsigned int strength, delay, count;
  double t0; /* absolute unix time when effect was started t_effect=0 */
  double t; /* current time when effect envelope is to be calculated */
  /* immediately convert timeval to double to simplyfy handling */
  int countdown; /* effect countdown counter */
  struct timeval timer_cont; /* continuation timer */
  unsigned char led; /* green LED */
  unsigned char ringer; /* ringer status */
  char data[20]; /* previous data received from the phone */
  int custom_len; /* custom effect upload length */
  unsigned char custom_data[16]; /* custom data */
  time_t zaptime;
  int zaphold;
};

struct handset handset;


/* get absoulte current time 
*/
double current_time()
{
  struct timeval current_time;

  gettimeofday(&current_time, NULL);
  return (double)current_time.tv_sec + 1.0e-6 * (double)current_time.tv_usec;  
}



/* This initializes libusb and tracks down the device
*/
static struct usb_device *init_device()
{
  struct usb_bus *bus;
  struct usb_device *dev;
  
  usb_init();
  usb_find_busses();
  usb_find_devices();
  
  for (bus = usb_busses; bus; bus = bus->next)
  {
    for (dev = bus->devices; dev; dev = dev->next)
    {
      if ((dev->descriptor.idVendor == usb_phone_vendor) &&
          (dev->descriptor.idProduct == usb_phone_product))
        return dev;
    }
  }
  return NULL;
}


/* register the phone in uinput system as
** pointing device with
** a number of keys, relative pointers and leds
** then it will automatically appear as /dev/input/phone*
*/
int handset_register(struct handset *phone)
{
  int aux, fd;

  /* libusb initialization */

  phone->dev = init_device();
  if(!phone->dev)
  {
    printf("Unable to find device.\n");
    return 1;
  }
  
  /* Open device, note: we want interface zero so we only have to open
     once */
  phone->handle = usb_open(phone->dev);
  if(!phone->handle)
  {
    printf("Unable to open device.\n");
    return 1;
  }

#if 0
  /* device doesn't accept configuration change ! */
  if(usb_set_configuration(phone->handle, 1))
  {
    printf("Failed to set config 1: EBUS: %d ENONM: %d\n", EBUSY, ENOMEM);
    return 1;
  }
#endif

  /* The keypad, led and ringer are at interface 3 */
  if(usb_claim_interface(phone->handle, 3) < 0)
  {
    printf("Unable to claim interface 3.\n");
    return 1;
  }

  /* uinput initialization */
  FD_ZERO(&fd_request_read);
  FD_ZERO(&fd_request_write);
  FD_ZERO(&fd_request_except);
  
  /* open uinput device file */
  fd = open("/dev/input/uinput", O_RDWR | O_NONBLOCK);
  if (fd < 0) {
    perror("open");
    return -1;
  }

  phone->uifd = fd;

  /* sets the name of our device */
  strcpy(phone->device.name, "BeyondTel USB Phone");

  /* sets maximum number of simultaneous force feedback effects */
  /* report kernel bug - not setting this leads to kernel oops */
#if HAVEFF
  phone->device.ff_effects_max = 1;
#endif
  
  /* its bus */
  phone->device.id.bustype = BUS_USB;
  
  /* and id/vendor id/product id/version
  ** we will create with uinput
  ** (not need to be the same as the hardware phone)
  */
  phone->device.id.vendor = usb_phone_vendor;
  phone->device.id.product = usb_phone_product;
  phone->device.id.version = 257;
  
  /* inform that we'll generate key events */
  ioctl(fd, UI_SET_EVBIT, EV_KEY);

  /* set keyboard events we can generate */
  for (aux = 0; keys[aux][0] < KEY_MAX; aux++)
  {
    ioctl(fd, UI_SET_KEYBIT, keys[aux][0]);
    /* keyboard translation table */
    scan2code[keys[aux][1]] = keys[aux][0];
  }

  /* inform that we have ringer */
  ioctl(fd, UI_SET_EVBIT, EV_SND);

  /* set sound we can ring bell */
  ioctl(fd, UI_SET_SNDBIT, SND_BELL);
  
  /* inform that we have force feedback - hack to use LCD */
#if HAVEFF
  ioctl(fd, UI_SET_EVBIT, EV_FF);

  /* set force feedback events - custom container for LCD control */
  ioctl(fd, UI_SET_FFBIT, FF_PERIODIC);
  ioctl(fd, UI_SET_FFBIT, FF_CUSTOM);
#endif

  /* inform that we have LED */
  ioctl(fd, UI_SET_EVBIT, EV_LED);

  /* set LED we can display */
  ioctl(fd, UI_SET_LEDBIT, LED_NUML);

  /* write down information for creating a new device */
  if (write(fd, &(phone->device), sizeof(struct uinput_user_dev)) < 0) {
    perror("write");
    close(fd);
    return 1;
  }

  /* actually creates the device */
  ioctl(fd, UI_DEV_CREATE);
  
  /* now we can register our uinput device for select() */
  FD_SET(fd, &fd_request_read);
  if(fd >= fd_count)
    fd_count = fd + 1;

  /* start with LED off */
  phone->led = 0;

  /* start with ringer off */
  phone->ringer = 0;
  
  memset(&(phone->timer_cont), 0, sizeof(phone->timer_cont));

  return 0;
}


/* wait for file descriptors.
** waits for vibration commands
** from uinput system, or for timeouts
** in order to continue lengthy vibrations
*/
int handset_wait(struct handset *phone)
{
  int n;
  struct timeval *timeout;

  timeout = &(phone->timer_cont);

  if(timeout->tv_sec == 0 && timeout->tv_usec == 0)
    timeout = NULL;

  memcpy(&fd_read, &fd_request_read, sizeof(fd_set));
  memcpy(&fd_write, &fd_request_write, sizeof(fd_set));
  memcpy(&fd_except, &fd_request_except, sizeof(fd_set));
  n = select(fd_count, &fd_read, &fd_request_write, &fd_request_except, timeout );

  return 0;
}


/* unregister the phone from uinput system
*/
int handset_unregister(struct handset *phone)
{
  /* uinput de-initialization */
  close(phone->uifd);

  /* libusb de-initialization */
  usb_close(phone->handle);

  return 0;
}


int set_led(struct handset *phone)
{
  char buffer[20];
  int ret;

  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);

  if(phone->led)
    ret = usb_interrupt_write(phone->handle, 1, led1, sizeof(led1), 5000);
  else
    ret = usb_interrupt_write(phone->handle, 1, led0, sizeof(led0), 5000);

  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);
  
  return 0;
}

int set_ringer(struct handset *phone)
{
  char buffer[20];
  int ret;

  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);

  if(phone->ringer)
    ret = usb_interrupt_write(phone->handle, 1, ring1, sizeof(ring1), 5000);
  else
    ret = usb_interrupt_write(phone->handle, 1, ring0, sizeof(ring0), 5000);
  
  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);

  return 0;
}

int set_lcd(struct handset *phone)
{
  char buffer[20];
  struct lcdpacket display[1];
  unsigned char *packetdisp;
  int ret;
  int i;
  display->type = 3;
  memset(display->unknown, 0, sizeof(display->unknown));
  memcpy(display->bitmap, phone->custom_data, sizeof(display->bitmap));

#if 0
  packetdisp = (unsigned char *)display;
  for(i = 0; i < sizeof(display); i++)
    printf("%02x ", packetdisp[i]);
  printf("\n");
#endif

  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);
  ret = usb_interrupt_write(phone->handle, 1, (unsigned char *)display, sizeof(display), 5000);
  ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);

  return 0;
}


/* process uinput event (ringer and LED) */
int uinput_event(struct handset *phone)
{
  struct input_event      event, received_event;
  struct uinput_ff_upload ff_up;
  struct uinput_ff_erase  ff_erase;
  int fd;
  int                     long_count;
  int i;

  fd = phone->uifd;

  if(read(fd, &received_event, sizeof(received_event)) == sizeof(received_event))
  {
    switch(received_event.type)
    {
    case EV_LED:
      switch(received_event.code)
      {
      case LED_NUML:
        phone->led = received_event.value > 0 ? 1 : 0;
#if 0
        printf("LED=%d cnt=%d\n", phone->led, ledcounter++);
#endif
        set_led(phone);
        break;
      }
      break;
    case EV_SND:
      switch(received_event.code)
      {
      case SND_BELL:
        phone->ringer = received_event.value > 0 ? 1 : 0;
        set_ringer(phone);
        break;
      }
      break;
#if HAVEFF
    case EV_UINPUT:
      switch(received_event.code)
      {
      case UI_FF_UPLOAD:
        printf("Effect upload requested.\n");
        ff_up.request_id = received_event.value;
        if(ioctl(fd, UI_BEGIN_FF_UPLOAD, &ff_up) < 0) {
          perror("ioctl UI_BEGIN_FF_UPLOAD");
          return;
        }
        /* upload effect (ff_up.request_id, ff_up.effect) */
        switch(ff_up.effect.type)
        {
        case FF_PERIODIC:
          switch(ff_up.effect.u.periodic.waveform)
          {
          case FF_CUSTOM:
             memcpy(phone->custom_data, &(ff_up.effect.u.periodic.period), 
               sizeof(phone->custom_data));
#if 0
             printf("Our struct ");
             for(i = 0; i < sizeof(phone->custom_data); i++)
               printf("%02x ", phone->custom_data[i]);
             printf("\n");
#endif
             set_lcd(phone);
             ff_up.retval = 0;
             ff_up.effect.id = 0;
             break;
          }
          break;
        }
        if(ioctl(fd, UI_END_FF_UPLOAD, &ff_up) < 0) {
          perror("ioctl UI_END_FF_UPLOAD");
          return;
        }
        break;
      case UI_FF_ERASE:
        ff_erase.request_id = received_event.value;
        if(ioctl(fd, UI_BEGIN_FF_ERASE, &ff_erase) < 0) {
          perror("ioctl UI_BEGIN_FF_ERASE");
        }
        phone->custom_len = 0;
        // memset(phone->custom_data, 0, sizeof(phone->custom_data));
        printf("request_id=%d effect_id=%d erased.\n", ff_erase.request_id, ff_erase.effect_id);
        ff_erase.retval = 0;
        if(ioctl(fd, UI_END_FF_ERASE, &ff_erase) < 0) {
          perror("ioctl UI_END_FF_UPLOAD");
        }
        break;
      }
      break;
#endif

    }
  }
#if 0
  else
    puts("uinput event wrong size...");
#endif
  
  return 0;
}


/* create single thread containing all here */
void *uinput_handler(void *data)
{
  struct handset *phone = (struct handset *) data;
  int i, n;

  /* loop processing events */
  for(;;)
  {
    /* wait for events from uinput */
    handset_wait(phone);

    /* is this uinput event? */
    if(FD_ISSET(phone->uifd, &fd_read))
    {
#if MUTEX
      pthread_mutex_lock(&mutex1);
#endif
      uinput_event(phone);
#if MUTEX
      pthread_mutex_unlock(&mutex1);
#endif
    }
    else
    {
#if 0
      /* no, this could be timer-based continuation */
      if(phone->countdown)
        handset_vibrate(phone, 1);
#endif
    }
  }

  return NULL;
}


/* warning track keys if many of them are pressed
** need to generate key up - key down events inbetween
*/
int key_event(struct handset *phone, char *buffer)
{
  struct input_event event;

  if( buffer[1] != phone->data[1] )
  {
#if MUTEX
    pthread_mutex_lock(&mutex1);
#endif

  if( phone->data[1] != 0 && phone->data[1] < SCANMAX )
  {
    event.type = EV_KEY;
    event.code = scan2code[phone->data[1]];
    event.value = 0;
    write(phone->uifd, &event, sizeof(struct input_event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(phone->uifd, &event, sizeof(struct input_event));

  }

  if( buffer[1] != 0 && buffer[1] < SCANMAX )
  {

    event.type = EV_KEY;
    event.code = scan2code[buffer[1]];
    event.value = 1;
    write(phone->uifd, &event, sizeof(struct input_event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(phone->uifd, &event, sizeof(struct input_event));        

  }

    fsync(phone->uifd);
#if MUTEX
    pthread_mutex_unlock(&mutex1);
#endif
  
  }

  return 0;
}


void *keypad_handler(void *data)
{
  struct handset *phone = (struct handset *) data;
  struct input_event event;
  int i, j, ret, change, fd;
  char buffer[20];

  fd = phone->uifd;
  for(;;)
  {
#if MUTEX
    pthread_mutex_lock(&mutex1);
#endif
    ret = usb_interrupt_read(phone->handle, 1, buffer, 17, 5000);
#if MUTEX
    pthread_mutex_unlock(&mutex1);
#endif

    if(ret < 0) {
      printf("Failure usb_interrupt_read  %d '%s'\n", ret, strerror(-ret));
    }
#if 0
    printf("Read %d bytes: ", ret);
    for(j = 0; j < ret; j++)
      printf("%02x ",
             ((int)buffer[j] & 0x0ff));
    printf("\n");
#endif
    /* decode event */

    /* In vague hallucination I have not heard
    ** master Yoda say:
    **
    ** mutexing this and uinput for
    ** kernel 2.6.13.4 crash prevent could not not
    ** but rather delayed would
    */
    if(ret == 17)
    {
      key_event(phone, buffer);

      memcpy(phone->data, buffer, 17);
    }
    /* here we can process uinput event in-thread 
    ** beware of blocking
    */
    #if THREAD
    #else
    uinput_event(phone);
    #endif
  }

  return NULL;
}


void terminate(int signal)
{
#if THREAD
  pthread_cancel(thread[0]);
  pthread_cancel(thread[1]);
#endif
}


int main(int argc, char *argv[])
{
  int i, n = THREADS;
  struct handset *phone = &handset;

  if(argc >= 2 && argc <= 3)
  {
    int detach = 0;
    char* const HEXPREFIX = "0x";
    unsigned char const HEXPREFIXLEN = 2;
    unsigned char const HEXSTRINGLEN = 6;
    unsigned char const HEXNUMLEN = 4;
    char vendor_id_s[HEXSTRINGLEN + 1], product_id_s[HEXSTRINGLEN + 1];
    
    if(*argv[1] == '-')
    {
      if(argv[1][1] == 'd')
      {
        detach = 1;
        argc--;
        argv++;
      }
      else
      {
        fprintf(stderr, "Usage: %s <-d> <hex_vendor_id:hex_product_id>\n", argv[0]);
        fprintf(stderr, "   Eg: %s -d %04x:%04x\n", argv[0], usb_phone_vendor, usb_phone_product);
        return 0;
      }
    }

    if(argc == 2)
    {
      memcpy(vendor_id_s, HEXPREFIX, HEXPREFIXLEN);
      strncpy(vendor_id_s + HEXPREFIXLEN, argv[1], HEXNUMLEN);
      usb_phone_vendor = 0xffff & strtol(vendor_id_s, NULL, 16);

      memcpy(product_id_s, HEXPREFIX, HEXPREFIXLEN);
      strncpy(product_id_s + HEXPREFIXLEN, argv[1] + HEXNUMLEN + 1, HEXNUMLEN);
      usb_phone_product = 0xffff & strtol(product_id_s, NULL, 16);
    }

    if(detach)
    {
      HIDInterface* hid;
      hid_return ret;

      fprintf(stderr, "Trying to detach HID with IDs %04x:%04x... ",
              usb_phone_vendor, usb_phone_product);

      HIDInterfaceMatcher matcher = { usb_phone_vendor, usb_phone_product, NULL, NULL, 0 };

      ret = hid_init();
      if (ret != HID_RET_SUCCESS) {
        fprintf(stderr, "hid_init failed with return code %d.\n", ret);
        return 1;
      }

      hid = hid_new_HIDInterface();
      if (hid == 0) {
        fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n");
        return 1;
      }
      
      ret = hid_force_open(hid, 0, &matcher, 3);
      if (ret != HID_RET_SUCCESS) {
        fprintf(stderr, "hid_force_open failed with return code %d.\n", ret);
        return 1;
      }
      
      ret = hid_close(hid);
      if (ret != HID_RET_SUCCESS) {
        fprintf(stderr, "hid_close failed with return code %d.\n", ret);
        return 1;
      }
      
      hid_delete_HIDInterface(&hid);

      ret = hid_cleanup();
      if (ret != HID_RET_SUCCESS) {
        fprintf(stderr, "hid_cleanup failed with return code %d.\n", ret);
        return 1;
      }
      
      fprintf(stderr, "done.\n");
      
    }
  }

  if(handset_register(phone))
  {
    printf("Cannot open device\n");
    return -1;
  }
  
  printf("User space driver (uinput) for BeyondTel USB Phone.\n");
  /* Create 2 independant threads
  ** one for force feedback handler
  ** second for normal phone events (kays and movement)
  */

#if THREAD
  /* this is pthread version */
  i = 0;
  if( (rc[i] = pthread_create( &thread[i], NULL, &uinput_handler, (void *) (phone) )) )
    printf("Thread creation failed: %d\n", rc[i]);

  i = 1;
  if( (rc[i] = pthread_create( &thread[i], NULL, &keypad_handler, (void *) (phone) )) )
    printf("Thread creation failed: %d\n", rc[i]);

  /* graceful exit handler */
  signal(SIGINT, &terminate);
  signal(SIGTERM, &terminate);

  /* Wait till threads are complete before main continues. Unless we  */
  /* wait we run the risk of executing an exit which will terminate   */
  /* the process and all threads before the threads have completed.   */
  
  pthread_join( thread[0], NULL);
  pthread_join( thread[1], NULL);
#else
  keypad_handler(phone);
#endif

  /* try single execution no-thread version */

  handset_unregister(phone);
  printf("exit.\n");
  
  return 0;
}
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HAVEFF 0

int main(int argc, char *argv[])
{
  struct input_event play;
  struct input_event stop;
  struct ff_effect *effect;
  int fd;
  int gain = 10; /* 0-100 */
  char name[256] = "Unknown";
  unsigned char 
  display_time[] = { 
  0x10,0xbe,0x5e,0x40,0x7c,0xc6,0xbf,0xe5,0x70,0x60,0x00,0x10,0x10,0x10,0x10,0x10
  },
  display_offhook[] = { 
  0x11,0xbe,0x5e,0x40,0x7c,0xc6,0xfb,0xeb,0x70,0x60,0x00,0x10,0x10,0x10,0x10,0x10
  }
  ;
  int retval;
  int i;

  effect = malloc(sizeof(struct ff_effect) + 16);
  memset(effect, 0, sizeof(struct ff_effect));

  if(argc < 2)
  {
    printf("usage: fftest /dev/input/eventX\n");
    return 0;
  }
  fd = open(argv[1], O_RDWR | O_SYNC);
  
  if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
    perror("evdev ioctl");
  }
  printf("%s: %s\n", argv[1], name);

#if HAVEFF
  memset(effect, 0, sizeof(struct ff_effect));

  /* fill the effect structure */
  effect->type = FF_PERIODIC;
  effect->id = -1; /* generate new effect */
  effect->u.periodic.waveform = FF_CUSTOM;
  /* dirty hack */
  memcpy(&effect->u.periodic.period, display_offhook, sizeof(display_offhook));
  
  /* upload the effect */
  retval = ioctl(fd, EVIOCSFF, effect);
  if (retval < 0)
  {
    printf("cannot upload the effect\n");
  }
  else
  {
    printf("effect %d uploaded.\n", effect->id);

    /* Remove the effect */
    retval = ioctl(fd, EVIOCRMFF, effect->id);
    if (retval < 0)
      printf("cannot remove the effect %d\n", effect->id);
  }
#endif

#if 1
  /* turn RINGER on */
  play.type = EV_SND;
  play.code = SND_BELL;
  play.value = 1;
  write(fd, (const void*) &play, sizeof(play));
#endif

  for(i = 0; i < 2; i++)
  {
  /* turn LED on */
  play.type = EV_LED;
  play.code = LED_NUML;
  play.value = 1;
  write(fd, (const void*) &play, sizeof(play));
  fsync(fd);

  usleep(100000);

  /* turn LED off */
  play.type = EV_LED;
  play.code = LED_NUML;
  play.value = 0;
  write(fd, (const void*) &play, sizeof(play));
  fsync(fd);
  
  usleep(100000);
  }

#if 1
  /* turn RINGER off */
  play.type = EV_SND;
  play.code = SND_BELL;
  play.value = 0;
  write(fd, (const void*) &play, sizeof(play));
#endif

#if HAVEFF
  /* fill the effect structure */
  effect->type = FF_PERIODIC;
  effect->id = -1; /* generate new effect */
  effect->u.periodic.waveform = FF_CUSTOM;
  /* dirty hack */
  memcpy(&effect->u.periodic.period, display_time, sizeof(display_time));
  
  /* upload the effect */
  retval = ioctl(fd, EVIOCSFF, effect);
  if (retval < 0)
  {
    printf("cannot upload the effect\n");
  }
  else
  {
    printf("effect %d uploaded.\n", effect->id);

    /* Remove the effect */
    retval = ioctl(fd, EVIOCRMFF, effect->id);
    if (retval < 0)
      printf("cannot remove the effect %d\n", effect->id);
  }
#endif

  close(fd);
  
  return 0;
}
/*
 * testlibusb.c
 *
 *  Test suite program
 */

#include <stdio.h>
#include <string.h>
#include <usb.h>
#include <string.h>
#include <asm/errno.h>

/* bind on this vendor/product */
#include "usbid.h"

char led0[] = { 
0x01,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
};

char led1[] = { 
0x01,0x11,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
};

char display_time[] = {
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x10,0xbe,0x5e,0x40,0x7c,0xc6,0xbf,0xe5,0x70,0x60,0x00,0x10,0x10,0x10,0x10,
0x10,
};

char display_offhook[] = {
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x11,0xbe,0x5e,0x40,0x7c,0xc6,0xfb,0xeb,0x70,0x60,0x00,0x10,0x10,0x10,0x10,
0x10
};

char display_000[] = {
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x11,0x00,0x00,0x00,0x00,0x00,0xeb,0xeb,0xff,0xff,0xeb,0xfb,0xeb,0xeb,0xfb,
/*                                    0    0   :8   :8    0   |0    0   |0    0  */
0xeb
/* 0 */
};

char ring1[] = {
0x01,0xff,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};

char ring0[] = {
0x01,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};

#define MAX_USB_MICE 10
struct usb_device* usb_mouse[MAX_USB_MICE];
int miceFound = 0;

int verbose = 0;

void do_usbmouse(struct usb_device *dev) {
  usb_dev_handle *mouse_device = 0;
  int ret = 0;
  int i, j ;

  printf("Doing usbmouse\n");
  if(dev->descriptor.idVendor != USB_MOUSE_VENDOR ||
     dev->descriptor.idProduct != USB_MOUSE_PRODUCT) {
    printf("ERR: Wasn't passed a usbmouse!\n");
    return;
  }
  if (dev->descriptor.iSerialNumber) {
    printf("Processing usb mouse id ...\n");
  } else {
    printf("Curious, device has no serial number.\n");
  }
  mouse_device = usb_open(dev);
  if(mouse_device > 0) {
    char buffer[512];
#if 0
    ret = usb_set_configuration(mouse_device, dev->config->bConfigurationValue);
    if(ret < 0) {
      printf("Failed to set config 1: %d EBUS: %d ENONM: %d\n", ret, EBUSY, ENOMEM);
      goto bail;
    }
#endif

    ret = usb_claim_interface(mouse_device, 3);
    if(ret < 0) {
      printf("Failed to claim interface 3: %d EBUS: %d ENONM: %d\n", ret, EBUSY, ENOMEM);
      goto bail;
    }
    
    /* send some message to the device */
    ret = usb_interrupt_write(mouse_device, 1, display_000, sizeof(display_000), 5000);
    ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);

    // ret = usb_interrupt_write(mouse_device, 1, ring1, sizeof(ring1), 5000);
    // ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);

    ret = usb_interrupt_write(mouse_device, 1, led1, sizeof(led1), 5000);
    i = 2000;
    while(i--) {
      ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);
      if(ret < 0) {
        printf("Failure usb_interrupt_read  %d '%s'\n", ret, strerror(-ret));
        goto bail;
      } 
      printf("%04x Read %d bytes: ", i, ret);
      for(j = 0; j < ret; j++) {
        printf("%02x ",
               ((int)buffer[j] & 0x0ff));
      }
      printf("\n");
    }
    ret = usb_interrupt_write(mouse_device, 1, led0, sizeof(led1), 5000);
    ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);

    ret = usb_interrupt_write(mouse_device, 1, display_time, sizeof(display_time), 5000);
    ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);

    ret = usb_interrupt_write(mouse_device, 1, ring0, sizeof(ring0), 5000);
    ret = usb_interrupt_read(mouse_device, 1, buffer, 17, 5000);

  bail:
    usb_close(mouse_device);
  }
}

void print_endpoint(struct usb_endpoint_descriptor *endpoint)
{
  printf("      bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
  printf("      bmAttributes:     %02xh\n", endpoint->bmAttributes);
  printf("      wMaxPacketSize:   %d\n", endpoint->wMaxPacketSize);
  printf("      bInterval:        %d\n", endpoint->bInterval);
  printf("      bRefresh:         %d\n", endpoint->bRefresh);
  printf("      bSynchAddress:    %d\n", endpoint->bSynchAddress);
}

void print_altsetting(struct usb_interface_descriptor *interface)
{
  int i;

  printf("    bInterfaceNumber:   %d\n", interface->bInterfaceNumber);
  printf("    bAlternateSetting:  %d\n", interface->bAlternateSetting);
  printf("    bNumEndpoints:      %d\n", interface->bNumEndpoints);
  printf("    bInterfaceClass:    %d\n", interface->bInterfaceClass);
  printf("    bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
  printf("    bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
  printf("    iInterface:         %d\n", interface->iInterface);

  for (i = 0; i < interface->bNumEndpoints; i++)
    print_endpoint(&interface->endpoint[i]);
}

void print_interface(struct usb_interface *interface)
{
  int i;

  for (i = 0; i < interface->num_altsetting; i++)
    print_altsetting(&interface->altsetting[i]);
}

void print_configuration(struct usb_config_descriptor *config)
{
  int i;

  printf("  wTotalLength:         %d\n", config->wTotalLength);
  printf("  bDescriptorType:      %d\n", config->bDescriptorType);
  printf("  bNumInterfaces:       %d\n", config->bNumInterfaces);
  printf("  bConfigurationValue:  %d\n", config->bConfigurationValue);
  printf("  iConfiguration:       %d\n", config->iConfiguration);
  printf("  bmAttributes:         %02xh\n", config->bmAttributes);
  printf("  MaxPower:             %d\n", config->MaxPower);

  for (i = 0; i < config->bNumInterfaces; i++)
    print_interface(&config->interface[i]);
}

void found_usb_mouse(struct usb_device *dev) {
  if(miceFound < MAX_USB_MICE) {
    usb_mouse[miceFound++] = dev;
    if(verbose) printf("Found usb mouse fob #%d\n", miceFound);
  }
}

int print_device(struct usb_device *dev, int level)
{
  usb_dev_handle *udev;
  char description[256];
  char string[256];
  int ret, i;

  udev = usb_open(dev);
  if (udev) {
    if (dev->descriptor.iManufacturer) {
      ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, string, sizeof(string));
      if (ret > 0) {
        snprintf(description, sizeof(description), "(%04X)",
                 dev->descriptor.idVendor);
        snprintf(description+strlen(description), sizeof(description)-strlen(description), "%s ~ ", string);
      } else {
        snprintf(description, sizeof(description), "%04X - ",
                 dev->descriptor.idVendor);
      }
    } else {
      snprintf(description, sizeof(description), "%04X - ",
               dev->descriptor.idVendor);
    }

    if (dev->descriptor.iProduct) {
      ret = usb_get_string_simple(udev, dev->descriptor.iProduct, string, sizeof(string));
      if (ret > 0) {
        snprintf(description + strlen(description), sizeof(description) -
                 strlen(description), "(%04X)", dev->descriptor.idProduct);
        snprintf(description + strlen(description), sizeof(description) -
                 strlen(description), "%s", string);
      } else
        snprintf(description + strlen(description), sizeof(description) -
                 strlen(description), "%04X", dev->descriptor.idProduct);
    } else
      snprintf(description + strlen(description), sizeof(description) -
               strlen(description), "%04X", dev->descriptor.idProduct);

  } else
    snprintf(description, sizeof(description), "%04X - %04X",
             dev->descriptor.idVendor, dev->descriptor.idProduct);

  printf("%.*sDev #%d: %s\n", level * 2, "                    ", dev->devnum,
         description);

  if (udev && verbose) {
    if (dev->descriptor.iSerialNumber) {
      ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, string, sizeof(string));
      if (ret > 0)
        printf("%.*s  - Serial Number: %s\n", level * 2,
               "                    ", string);
    }
  }

  if (udev)
    usb_close(udev);

  if (verbose) {
    if (!dev->config) {
      printf("  Couldn't retrieve descriptors\n");
      return 0;
    }

    for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
      print_configuration(&dev->config[i]);
  } else {
    for (i = 0; i < dev->num_children; i++) {
      print_device(dev->children[i], level + 1);
	if(dev->children[i]->descriptor.idVendor == USB_MOUSE_VENDOR &&
	   dev->children[i]->descriptor.idProduct == USB_MOUSE_PRODUCT) {
	  found_usb_mouse(dev->children[i]);
	}
    }
  }

  return 0;
}

int main(int argc, char *argv[])
{
  struct usb_bus *bus;
  int bus_changes = 0;
  int dev_changes = 0;
  int i;

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

  usb_init();

#if 1
  bus_changes = usb_find_busses();
  if(verbose) printf("Bus changes: %d\n", bus_changes);
  dev_changes = usb_find_devices();
  if(verbose) printf("Dev changes: %d\n", dev_changes);
#endif


  for (bus = usb_busses; bus; bus = bus->next) {
    struct usb_device *dev;
    for (dev = bus->devices; dev; dev = dev->next) {
      print_device(dev, 0);
      if(dev->descriptor.idVendor == USB_MOUSE_VENDOR &&
         dev->descriptor.idProduct == USB_MOUSE_PRODUCT) {
        found_usb_mouse(dev);
      }
    }
  }

  for(i = 0; i < miceFound && i < 1; i++) {
    do_usbmouse(usb_mouse[i]);
  }
  return 0;
}
all: testlibusb skypephone iftest

# this is for logitech iFeel mouse
usbid=04b4:0302
# this is for cypress mouse
#usbid=05fe:0011

skypephone: skypephone.c
	cc -lusb -lhid -lpthread -o $@ $<

iftest: iftest.c
	cc $< -o $@
        
testlibusb: testlibusb.c
	cc -lusb -o $@ $<
	
testrawhid: testrawhid.c
	cc -o $@ $<

detach:
	libhid-detach-device $(usbid)

info:
	lsusb -vvv -d $(usbid)

testui: ifeel iftest detach
	./ifeel -d $(usbid) &
	sleep 1
	./iftest /dev/input/event4
	sleep 1
	killall ifeel

testusb: testlibusb
	./testlibusb -v

clean:
	rm -f DEADJOE *~
	rm -f skypephone.o skypephone iftest iftest.o testlibusb
/* Skype@Phone EX-B */
#define USB_MOUSE_VENDOR   0x04b4
#define USB_MOUSE_PRODUCT  0x0302

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux