RE: [PATCH] hid: usbhid: New hid quirks for Panasonic ElitePanaboard T-780 and T-880

From: Anton Chikin
Date: Thu Nov 18 2010 - 12:00:03 EST


Hello Jiri,

Actually our driver is implemented as the fork of usbhid driver. I'm now trying to move to HID bus. I think I need some help with this.
I've copied /drivers/hid/hid-cando.c source code, changed device IDs in hid_driver structure, added my device IDs to /drivers/hid/hid-core.c hid_blacklist[] array, but my probe() method still never get called. Could you please help me with this?

My driver code and Makefile are in attachment.

Thank you.

-----Original Message-----
From: Jiri Kosina [mailto:jkosina@xxxxxxx]
Sent: Wednesday, November 03, 2010 4:28 PM
To: Anton Chikin
Cc: chatty@xxxxxxx; spbnick@xxxxxxxxx; anisse@xxxxxxxxx; cascardo@xxxxxxxxxxxxxx; linux-input@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx; Gregory Burmistrov; Paul Osborn
Subject: RE: [PATCH] hid: usbhid: New hid quirks for Panasonic Elite Panaboard T-780 and T-880

On Tue, 2 Nov 2010, Anton Chikin wrote:

> Thank you for your feedback.
>
> With the generic hid driver device is working in mouse-mode, turning
> it into the huge touchscreen, which is completely useless for the end-user.

Still, at least some very basic and limited/crippled functionality is there. So my preferred mode of operation now would be having the device being claimed by generic driver and wait for your proper full-fledged driver.

> On some Linux systems hid driver is loaded from init.rd image, so we
> can't feed our quirks to it while boot process and we can't rebuild
> init.rd image on the user's machine because some Linux distributives
> doesn't have special tools preinstalled.
>
> We are going to submit our driver to the Linux kernel quickly, so
> everyone can improve it.

That would be great, I'll be happy to review and merge it. Are you planning to have it as a driver on HID bus, or completely separate USB driver?

Thanks,

--
Jiri Kosina
SUSE Labs, Novell Inc.
/*
* HID driver for Cando dual-touch panels
*
* Copyright (c) 2010 Stephane Chatty <chatty@xxxxxxx>
*
*/

/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/

#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>


#include "hid-ids.h"
#include "usbubt.h"
#define UBT780_DEBUG

#ifdef UBT780_DEBUG
#define UBT_DUMMY_DEBUG if(ubt_debug) printk(KERN_DEBUG "ubt780: %s:%s line %i\n", __FILE__,__FUNCTION__ , __LINE__);
#else
#define UBT_DUMMY_DEBUG
#endif

static int ubt_debug=0;
module_param_named(debug_enabled, ubt_debug, int, 0600);
MODULE_PARM_DESC(debug_enabled, "toggle UBT debugging messages");

struct ubt780_data {
struct ubt780_calib calib;
struct ubt780_dgtzr ubt_packet;
};

static int ubt780_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
UBT_DUMMY_DEBUG
switch (usage->hid & HID_USAGE_PAGE) {

case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
}
return 0;

case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_TIPSWITCH:
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_INRANGE:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
}
return 0;
}

return 0;
}

static int ubt780_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
UBT_DUMMY_DEBUG
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);

return 0;
}

/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void ubt780_filter_event(struct ubt780_data *td, struct input_dev *input)
{
//td->first = !td->first; /* touchscreen emulation */

//if (!td->valid) {
// /*
// * touchscreen emulation: if this is the second finger and
// * the first was valid, the first was the oldest; if the
// * first was not valid and there was a valid finger in the
// * previous frame, this is a release.
// */
// if (td->first) {
// td->firstid = -1;
// } else if (td->firstid >= 0) {
// input_event(input, EV_ABS, ABS_X, td->firstx);
// input_event(input, EV_ABS, ABS_Y, td->firsty);
// td->oldest = td->firstid;
// } else if (td->oldest >= 0) {
// input_event(input, EV_KEY, BTN_TOUCH, 0);
// td->oldest = -1;
// }

// return;
//}
//
//input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
//input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
//input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);

//input_mt_sync(input);

///*
// * touchscreen emulation: if there was no touching finger previously,
// * emit touch event
// */
//if (td->oldest < 0) {
// input_event(input, EV_KEY, BTN_TOUCH, 1);
// td->oldest = td->id;
//}

///*
// * touchscreen emulation: if this is the first finger, wait for the
// * second; the oldest is then the second if it was the oldest already
// * or if there was no first, the first otherwise.
// */
//if (td->first) {
// td->firstx = td->x;
// td->firsty = td->y;
// td->firstid = td->id;
//} else {
// int x, y, oldest;
// if (td->id == td->oldest || td->firstid < 0) {
// x = td->x;
// y = td->y;
// oldest = td->id;
// } else {
// x = td->firstx;
// y = td->firsty;
// oldest = td->firstid;
// }
// input_event(input, EV_ABS, ABS_X, x);
// input_event(input, EV_ABS, ABS_Y, y);
// td->oldest = oldest;
//}
}


static int ubt780_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct ubt780_data *td = hid_get_drvdata(hid);

UBT_DUMMY_DEBUG

if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;

switch (usage->hid) {
case HID_DG_INRANGE:
//td->valid = value;
UBT_DUMMY_DEBUG
break;
case HID_DG_CONTACTID:
//td->id = value;
UBT_DUMMY_DEBUG
break;
case HID_GD_X:
//td->x = value;
UBT_DUMMY_DEBUG
break;
case HID_GD_Y:
//td->y = value;
UBT_DUMMY_DEBUG
//ubt780_filter_event(td, input);
break;
case HID_DG_TIPSWITCH:
/* avoid interference from generic hidinput handling */
UBT_DUMMY_DEBUG
break;

default:
/* fallback to the generic hidinput handling */
return 0;
}
}

/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);

return 1;
}

static int ubt780_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct ubt780_data *td;

UBT_DUMMY_DEBUG

td = kmalloc(sizeof(struct ubt780_data), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate UB-T780 data\n");
return -ENOMEM;
}


hid_set_drvdata(hdev, td);
/*td->first = false;
td->oldest = -1;
td->valid = false;*/

ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);

if (ret)
kfree(td);

return ret;
}

static void ubt780_remove(struct hid_device *hdev)
{
UBT_DUMMY_DEBUG
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}

static struct hid_device_id ubt780_devices[] = {
{ HID_USB_DEVICE(0x04da, 0x1044) },
{ }
};
MODULE_DEVICE_TABLE(hid, ubt780_devices);

static const struct hid_usage_id ubt780_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};

static struct hid_driver ubt780_driver = {
.name = "ubt780",
.id_table = ubt780_devices,
.probe = ubt780_probe,
// .remove = ubt780_remove,
// .input_mapping = ubt780_input_mapping,
// .input_mapped = ubt780_input_mapped,
// .usage_table = ubt780_grabbed_usages,
// .event = ubt780_event,
};

static int __init ubt780_init(void)
{
UBT_DUMMY_DEBUG
int retval = hid_register_driver(&ubt780_driver);

if(retval)
UBT_DUMMY_DEBUG

return 0;
}

static void __exit ubt780_exit(void)
{
UBT_DUMMY_DEBUG
hid_unregister_driver(&ubt780_driver);
}

module_init(ubt780_init);
module_exit(ubt780_exit);

MODULE_AUTHOR("Anton Chikin <kverloin@xxxxxxxxx>");
MODULE_DESCRIPTION("Panasonic UB-T780 driver");
MODULE_LICENSE("GPL");

Attachment: Makefile
Description: Makefile