* Re: uinput oopses and bugs
[not found] ` <20080327202245.GK25854@cathedrallabs.org>
@ 2008-03-28 0:55 ` davor emard
2008-03-28 18:46 ` Anssi Hannula
0 siblings, 1 reply; 3+ messages in thread
From: davor emard @ 2008-03-28 0:55 UTC (permalink / raw)
To: Aristeu Rozanski; +Cc: linux-input
HI Aristeu
> first, please keep the mailing list on Cc. two reasons: first, I may not
> be able to answer other questions; second, other people may have the
> same problems you do and this discussion can be useful for them.
Last time the mail from the list bounced again although I've explicitely
subscribed to linux-input@vger.kernel.org but nevermind
>
> > Still the EV_FF makes EV_LED and EV_SND not working.
> will work on that next.
Hope the reproducer works for you, it's a bit clumsy written
but I hope it's useful to track this LED and SND disabling by
FF
> > There is also a still issue with segfault and unkillable driver.
> > I upload custom FF effect, driver segfaults but doesn't exit
> > and becomes zombie
> please test the attached patch
The patch now avoids the zombie lockup coming from segmentation
fault. Thanks a lot, that is great step forward!
However it's still not clear to me why do I get this segmentation
fault when I try to upload a block of FF_CUSTOM sample data.
I made my code mainly from looking at the kernel source without
having any example - anyone on the list can point link to some small
code example?
in uinput-zombie, I've prepared the data in application, ioctl'ed them
to uinput event device and the uinput driver segfaults when
it tries to read the portion of FF_CUSTOM data.
Best regards, Davor
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: uinput oopses and bugs
2008-03-28 0:55 ` uinput oopses and bugs davor emard
@ 2008-03-28 18:46 ` Anssi Hannula
2008-03-28 19:07 ` davor emard
0 siblings, 1 reply; 3+ messages in thread
From: Anssi Hannula @ 2008-03-28 18:46 UTC (permalink / raw)
To: davor emard; +Cc: Aristeu Rozanski, linux-input
davor emard wrote:
>>> There is also a still issue with segfault and unkillable driver.
>>> I upload custom FF effect, driver segfaults but doesn't exit
>>> and becomes zombie
>> please test the attached patch
>
> The patch now avoids the zombie lockup coming from segmentation
> fault. Thanks a lot, that is great step forward!
>
> However it's still not clear to me why do I get this segmentation
> fault when I try to upload a block of FF_CUSTOM sample data.
> I made my code mainly from looking at the kernel source without
> having any example - anyone on the list can point link to some small
> code example?
>
> in uinput-zombie, I've prepared the data in application, ioctl'ed them
> to uinput event device and the uinput driver segfaults when
> it tries to read the portion of FF_CUSTOM data.
I think uinput needs special handling for FF_CUSTOM to deliver the ff
data to userspace. AFAIK the segfault occurs because the uinput driver
tries to read the data pointer, while the data is only in kernel and not
copied to userspace.
I haven't seen any driver yet, uinput or in-kernel, that supports
FF_CUSTOM, so this could've been overlooked quite easily. It is in my
TODO to implement it for PID devices, but I do not have time anytime soon.
--
Anssi Hannula
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: uinput oopses and bugs
2008-03-28 18:46 ` Anssi Hannula
@ 2008-03-28 19:07 ` davor emard
0 siblings, 0 replies; 3+ messages in thread
From: davor emard @ 2008-03-28 19:07 UTC (permalink / raw)
To: Anssi Hannula; +Cc: Aristeu Rozanski, linux-input
[-- Attachment #1: Type: text/plain, Size: 625 bytes --]
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
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: skypephone.c --]
[-- Type: text/x-csrc; name=skypephone.c, Size: 19003 bytes --]
/* LICENSE=GPL */
/* iFeel force feedback uinput driver
** written by emard@softhome.net
*/
/* 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(¤t_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;
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: iftest.c --]
[-- Type: text/x-csrc; name=iftest.c, Size: 2931 bytes --]
#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;
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: testlibusb.c --]
[-- Type: text/x-csrc; name=testlibusb.c, Size: 9557 bytes --]
/*
* 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;
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: Makefile --]
[-- Type: text/x-makefile; name=Makefile, Size: 622 bytes --]
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
[-- Attachment #6: usbid.h --]
[-- Type: text/plain, Size: 91 bytes --]
/* Skype@Phone EX-B */
#define USB_MOUSE_VENDOR 0x04b4
#define USB_MOUSE_PRODUCT 0x0302
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-03-28 19:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <beee72200803260141y59b96c56n9fccfda6c72d1783@mail.gmail.com>
[not found] ` <20080326132844.GC25854@cathedrallabs.org>
[not found] ` <beee72200803260709p7239ae8etb4e00b608bbfb6bc@mail.gmail.com>
[not found] ` <20080326182314.GF25854@cathedrallabs.org>
[not found] ` <beee72200803270115v72eb1cd3s38ae90a4efd6acd1@mail.gmail.com>
[not found] ` <20080327202245.GK25854@cathedrallabs.org>
2008-03-28 0:55 ` uinput oopses and bugs davor emard
2008-03-28 18:46 ` Anssi Hannula
2008-03-28 19:07 ` davor emard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).