On Fri, 29 Sep 2006 16:24:15 +0800 raise.sail wrote:

> Changelogs:
> 
>       1. A bugfix for clear usage process.
> 
> This driver requires:
>       1.  [PATCH] usb: HID Simple Driver Interface 0.3.1 (Kconfig and 
> Makefile), this patch can be used without any change.
> 
> PS:   Who is the maintainer of the input subsystem today? Should I forward 
> this mail to him/her?

>From the MAINTAINERS file (and cc-ed):

INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS
P:      Dmitry Torokhov
M:      [EMAIL PROTECTED]
M:      [EMAIL PROTECTED]
L:      [EMAIL PROTECTED]
L:      [EMAIL PROTECTED]
T:      git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
S:      Maintained


> It can be applied on 2.6.18 at least. 
> 
> Signed-off-by: Liyu <[EMAIL PROTECTED]>
> 
> diff -Naurp linux-2.6.18/drivers/usb/input/hid-core.c 
> linux-2.6.18/drivers/usb/input.new/hid-core.c
> --- linux-2.6.18/drivers/usb/input/hid-core.c 2006-09-20 11:42:06.000000000 
> +0800
> +++ linux-2.6.18/drivers/usb/input.new/hid-core.c     2006-09-28 
> 09:30:47.000000000 +0800
> @@ -26,6 +26,7 @@
>  #include <asm/byteorder.h>
>  #include <linux/input.h>
>  #include <linux/wait.h>
> +#include <linux/mutex.h>
>  
>  #undef DEBUG
>  #undef DEBUG_DATA
> @@ -33,6 +34,7 @@
>  #include <linux/usb.h>
>  
>  #include "hid.h"
> +#include "hid-simple.h"
>  #include <linux/hiddev.h>
>  
>  /*
> @@ -46,6 +48,15 @@
>  
>  static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", 
> "Joystick",
>                               "Gamepad", "Keyboard", "Keypad", "Multi-Axis 
> Controller"};
> +
> +/*
> + * The global data structure for simple device driver interface.
> + */
> +static DEFINE_MUTEX(matched_devices_lock);
> +static DEFINE_MUTEX(simple_drivers_lock);
> +static struct list_head matched_devices_list;
> +static struct list_head simple_drivers_list;
> +
>  /*
>   * Module parameters.
>   */
> @@ -785,8 +796,18 @@ static __inline__ int search(__s32 *arra
>  static void hid_process_event(struct hid_device *hid, struct hid_field 
> *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs 
> *regs)
>  {
>       hid_dump_input(usage, value);
> -     if (hid->claimed & HID_CLAIMED_INPUT)
> +     if (hid->claimed & HID_CLAIMED_INPUT) {
> +             /* event filter here */
> +             if (hid->simple) {
> +                     if (hid->simple->pre_event &&
> +                             !hid->simple->pre_event(hid, field, usage, 
> +                                                             value, regs))
> +                     return;
> +             }
>               hidinput_hid_event(hid, field, usage, value, regs);
> +             if (hid->simple && hid->simple->post_event)
> +                     hid->simple->post_event(hid, field, usage, value, regs);
> +     }
>       if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
>               hiddev_hid_event(hid, field, usage, value, regs);
>  }
> @@ -832,7 +853,6 @@ static void hid_input_field(struct hid_d
>                       && field->usage[field->value[n] - min].hid
>                       && search(value, field->value[n], count))
>                               hid_process_event(hid, field, 
> &field->usage[field->value[n] - min], 0, interrupt, regs);
> -
>               if (value[n] >= min && value[n] <= max
>                       && field->usage[value[n] - min].hid
>                       && search(field->value, value[n], count))
> @@ -2031,8 +2051,33 @@ static void hid_disconnect(struct usb_in
>       del_timer_sync(&hid->io_retry);
>       flush_scheduled_work();
>  
> -     if (hid->claimed & HID_CLAIMED_INPUT)
> +     if (hid->claimed & HID_CLAIMED_INPUT) {
> +             struct list_head *node;
> +             struct matched_device *matched;
> +
> +             matched = NULL;
> +             mutex_lock(&matched_devices_lock);
> +             list_for_each(node, &matched_devices_list) {
> +                     matched = list_entry(node, struct matched_device, node);
> +                     if (matched->intf == intf) {
> +                             list_del(&matched->node);
> +                             break;
> +                     }
> +                     matched = NULL;
> +             }
> +             mutex_unlock(&matched_devices_lock);
> +             /* disconnect simple device driver if need */
> +             if (matched && hid->simple) {
> +                     hidinput_simple_driver_disconnect(hid);
> +                     module_put(hid->simple->owner);
> +                     hidinput_simple_driver_pop(hid, matched);
> +             }
> +             if (matched) {
> +                     matched->intf = NULL;
> +                     kfree(matched);
> +             }
>               hidinput_disconnect(hid);
> +     }
>       if (hid->claimed & HID_CLAIMED_HIDDEV)
>               hiddev_disconnect(hid);
>  
> @@ -2045,6 +2090,141 @@ static void hid_disconnect(struct usb_in
>       hid_free_device(hid);
>  }
>  
> +#ifdef CONFIG_HID_SIMPLE
> +static int hidinput_simple_driver_bind_one(struct hidinput_simple_driver 
> *simple,
> +                                                     struct hid_device *hid,
> +                                             struct matched_device *matched)
> +{
> +     int ret;
> +
> +     if (!try_module_get(simple->owner))
> +             return -ENODEV;
> +     ret = hidinput_simple_driver_connect(simple, hid);
> +     if (ret)
> +             goto exit_err;
> +     ret = hidinput_simple_driver_push(hid, simple, matched);
> +     if (ret)
> +             goto exit_err;
> +     hidinput_simple_driver_setup_usage(hid);
> +     printk(KERN_INFO "The Simple HID driver \'%s\' attach on \'%s\'\n",
> +                                             simple->name, hid->name);
> +     goto exit;
> +exit_err:
> +     module_put(simple->owner);
> +exit:
> +     return ret;
> +}
> +
> +static void hidinput_simple_driver_bind_foreach_simple(
> +                                             struct matched_device *matched)
> +{
> +     struct hidinput_simple_driver *simple;
> +     struct list_head *node;
> +     struct hid_device *hid;
> +     
> +     if (!matched->intf)
> +             return;
> +     hid = usb_get_intfdata (matched->intf);
> +     if (!hid || hid->simple)
> +             return;
> +
> +     mutex_lock(&simple_drivers_lock);
> +     list_for_each(node, &simple_drivers_list) {
> +             simple = list_entry(node, struct hidinput_simple_driver, node);
> +             if (test_bit(HIDINPUT_SIMPLE_CONNECTED, &simple->flags))
> +                     continue;
> +             if (usb_match_id(matched->intf, simple->id_table)) {
> +                     hidinput_simple_driver_bind_one(simple, hid, matched);
> +                     break;
> +             }
> +     }
> +     mutex_unlock(&simple_drivers_lock);
> +}
> +
> +static void hidinput_simple_driver_bind_foreach(void)
> +{
> +     struct hidinput_simple_driver *simple;
> +     struct matched_device *matched=NULL;
> +     struct list_head *matched_node = NULL;
> +     struct list_head *simple_node = NULL;
> +     struct hid_device *hid=NULL;
> +
> +     mutex_lock(&matched_devices_lock);
> +     list_for_each(matched_node, &matched_devices_list) {
> +             matched = list_entry(matched_node, struct matched_device, node);
> +             hid = usb_get_intfdata(matched->intf);
> +             if (hid->simple)
> +                     continue;
> +             mutex_lock(&simple_drivers_lock);
> +             list_for_each(simple_node, &simple_drivers_list) {
> +                     simple = list_entry(simple_node, struct 
> hidinput_simple_driver, node);
> +
> +                     if (test_bit(HIDINPUT_SIMPLE_CONNECTED, &simple->flags))
> +                             continue;
> +                     if (!usb_match_id(matched->intf, simple->id_table))
> +                             continue;
> +                     hidinput_simple_driver_bind_one(simple, hid, matched);
> +             }
> +             mutex_unlock(&simple_drivers_lock);
> +     }
> +     mutex_unlock(&matched_devices_lock);
> +}
> +
> +static void hidinput_simple_driver_bind_foreach_matched(
> +                                     struct hidinput_simple_driver *simple)
> +{
> +     struct list_head *node=NULL;
> +     struct matched_device *matched;
> +     struct hid_device *hid=NULL;
> +
> +     if (!simple || test_bit(HIDINPUT_SIMPLE_CONNECTED, &simple->flags))
> +             return;
> +
> +     mutex_lock(&matched_devices_lock);
> +     list_for_each(node, &matched_devices_list) {
> +             matched = list_entry(node, struct matched_device, node);
> +             hid = usb_get_intfdata (matched->intf);
> +             if (hid->simple)
> +                     continue;
> +             if (!usb_match_id(matched->intf, simple->id_table))
> +                     continue;
> +             hidinput_simple_driver_bind_one(simple, hid, matched);
> +     }
> +     mutex_unlock(&matched_devices_lock);
> +}
> +
> +int hidinput_register_simple_driver(struct hidinput_simple_driver *simple)
> +{
> +     if (!simple || !simple->name)
> +             return -EINVAL;
> +
> +     printk(KERN_INFO "The Simple HID driver \'%s\' register.\n", 
> +                                                             simple->name);
> +     hidinput_simple_driver_init(simple);
> +     hidinput_simple_driver_bind_foreach_matched(simple);
> +
> +     mutex_lock(&simple_drivers_lock);
> +     list_add(&simple->node, &simple_drivers_list);
> +     mutex_unlock(&simple_drivers_lock);
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL(hidinput_register_simple_driver);
> +
> +void hidinput_unregister_simple_driver(struct hidinput_simple_driver *simple)
> +{
> +     printk(KERN_INFO "The Simple HID driver \'%s\' unregister.\n", 
> +                                                     simple->name);
> +     hidinput_simple_driver_clear(simple);
> +     mutex_lock(&simple_drivers_lock);
> +     list_del(&simple->node);
> +     mutex_unlock(&simple_drivers_lock);
> +     /* to active simple device driver that it is waiting */
> +     hidinput_simple_driver_bind_foreach();
> +}
> +EXPORT_SYMBOL_GPL(hidinput_unregister_simple_driver);
> +#endif
> +
>  static int hid_probe(struct usb_interface *intf, const struct usb_device_id 
> *id)
>  {
>       struct hid_device *hid;
> @@ -2061,15 +2241,25 @@ static int hid_probe(struct usb_interfac
>       hid_init_reports(hid);
>       hid_dump_device(hid);
>  
> -     if (!hidinput_connect(hid))
> +     usb_set_intfdata(intf, hid);
> +
> +     if (!hidinput_connect(hid)) {
> +             struct matched_device *matched;
> +             matched = kmalloc(sizeof(struct matched_device), GFP_KERNEL);
> +             if (matched) {
> +                     matched->intf = intf;
> +                     mutex_lock(&matched_devices_lock);
> +                     list_add(&matched->node, &matched_devices_list);
> +                     mutex_unlock(&matched_devices_lock);
> +                     hidinput_simple_driver_bind_foreach_simple(matched);
> +             }
>               hid->claimed |= HID_CLAIMED_INPUT;
> +     }
>       if (!hiddev_connect(hid))
>               hid->claimed |= HID_CLAIMED_HIDDEV;
>  
> -     usb_set_intfdata(intf, hid);
> -
>       if (!hid->claimed) {
> -             printk ("HID device not claimed by input or hiddev\n");
> +             printk (KERN_INFO "HID device not claimed by input or 
> hiddev\n");
>               hid_disconnect(intf);
>               return -ENODEV;
>       }
> @@ -2168,6 +2358,8 @@ static int __init hid_init(void)
>       retval = hiddev_init();
>       if (retval)
>               goto hiddev_init_fail;
> +     INIT_LIST_HEAD(&matched_devices_list);
> +     INIT_LIST_HEAD(&simple_drivers_list);
>       retval = usb_register(&hid_driver);
>       if (retval)
>               goto usb_register_fail;
> @@ -2182,7 +2374,15 @@ hiddev_init_fail:
>  
>  static void __exit hid_exit(void)
>  {
> +     struct list_head *node, *tmp;
> +     struct matched_device *matched;
> +
>       usb_deregister(&hid_driver);
> +     list_for_each_safe(node, tmp, &matched_devices_list) {
> +             matched = list_entry(node, struct matched_device, node);
> +             list_del(&matched->node);
> +             kfree(matched);
> +     }
>       hiddev_exit();
>  }
>  
> diff -Naurp linux-2.6.18/drivers/usb/input/hid.h 
> linux-2.6.18/drivers/usb/input.new/hid.h
> --- linux-2.6.18/drivers/usb/input/hid.h      2006-09-20 11:42:06.000000000 
> +0800
> +++ linux-2.6.18/drivers/usb/input.new/hid.h  2006-09-28 09:28:15.000000000 
> +0800
> @@ -389,8 +389,11 @@ struct hid_input {
>       struct list_head list;
>       struct hid_report *report;
>       struct input_dev *input;
> +     void *private;
>  };
>  
> +struct hidinput_simple_driver;
> +
>  struct hid_device {                                                  /* 
> device report descriptor */
>        __u8 *rdesc;
>       unsigned rsize;
> @@ -454,6 +457,8 @@ struct hid_device {                                       
>                 /* device repo
>       int (*ff_event)(struct hid_device *hid, struct input_dev *input,
>                       unsigned int type, unsigned int code, int value);
>  
> +     struct hidinput_simple_driver *simple;
> +
>  #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
>       unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
>       unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
> diff -Naurp linux-2.6.18/drivers/usb/input/hid-input.c 
> linux-2.6.18/drivers/usb/input.new/hid-input.c
> --- linux-2.6.18/drivers/usb/input/hid-input.c        2006-09-20 
> 11:42:06.000000000 +0800
> +++ linux-2.6.18/drivers/usb/input.new/hid-input.c    2006-09-28 
> 09:28:15.000000000 +0800
> @@ -34,7 +34,7 @@
>  #undef DEBUG
>  
>  #include "hid.h"
> -
> +#include "hid-simple.h"
>  #define unk  KEY_UNKNOWN
>  
>  static const unsigned char hid_keyboard[256] = {
> @@ -61,6 +61,8 @@ static const struct {
>       __s32 y;
>  }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 
> 1}, {-1, 1}, {-1, 0}, {-1,-1}};
>  
> +typedef void (*do_usage_t)(struct hid_field *, struct hid_usage *);
> +
>  #define map_abs(c)   do { usage->code = c; usage->type = EV_ABS; bit = 
> input->absbit; max = ABS_MAX; } while (0)
>  #define map_rel(c)   do { usage->code = c; usage->type = EV_REL; bit = 
> input->relbit; max = REL_MAX; } while (0)
>  #define map_key(c)   do { usage->code = c; usage->type = EV_KEY; bit = 
> input->keybit; max = KEY_MAX; } while (0)
> @@ -747,8 +749,13 @@ static int hidinput_input_event(struct i
>       struct hid_field *field;
>       int offset;
>  
> -     if (type == EV_FF)
> +     if (type == EV_FF) {
> +             if (hid->simple && hid->simple->ff_event) {
> +                     if (!hid->simple->ff_event(dev, type, code, value));
> +                             return 0;
> +             }
>               return hid_ff_event(hid, dev, type, code, value);
> +     }
>  
>       if (type != EV_LED)
>               return -1;
> @@ -767,12 +774,22 @@ static int hidinput_input_event(struct i
>  static int hidinput_open(struct input_dev *dev)
>  {
>       struct hid_device *hid = dev->private;
> -     return hid_open(hid);
> +     int ret = 0;
> +
> +     if (hid->simple && hid->simple->open)
> +             ret = hid->simple->open(dev);
> +     if (!ret)
> +             return hid_open(hid);
> +     else
> +             return ret;
>  }
>  
>  static void hidinput_close(struct input_dev *dev)
>  {
>       struct hid_device *hid = dev->private;
> +
> +     if (hid->simple && hid->simple->close)
> +             hid->simple->close(dev);
>       hid_close(hid);
>  }
>  
> @@ -821,7 +838,7 @@ int hidinput_connect(struct hid_device *
>                               input_dev->event = hidinput_input_event;
>                               input_dev->open = hidinput_open;
>                               input_dev->close = hidinput_close;
> -
> +                             hidinput_simple_driver_ff_init(input_dev);
>                               input_dev->name = hid->name;
>                               input_dev->phys = hid->phys;
>                               input_dev->uniq = hid->uniq;
> diff -Naurp linux-2.6.18/drivers/usb/input/hid-simple.c 
> linux-2.6.18/drivers/usb/input.new/hid-simple.c
> --- linux-2.6.18/drivers/usb/input/hid-simple.c       1970-01-01 
> 08:00:00.000000000 +0800
> +++ linux-2.6.18/drivers/usb/input.new/hid-simple.c   2006-09-29 
> 09:22:38.000000000 +0800
> @@ -0,0 +1,315 @@
> +/*
> + *  HID Simple Driver Interface v0.3.2
> + * 
> + *  Copyright (c) 2006 Li Yu <[EMAIL PROTECTED]>
> + */
> +
> +/*
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + * Should you need to contact me, the author, you can do so either by
> + * e-mail - mail your message to <[EMAIL PROTECTED]>, or by paper mail:
> + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/input.h>
> +
> +#include "hid.h"
> +#include "hid-simple.h"
> +
> +typedef void (*do_usage_t)(struct hid_field *, struct hid_usage *);
> +
> +int hidinput_simple_driver_init(struct hidinput_simple_driver *drv)
> +{
> +     if (unlikely(!drv))
> +             return -EINVAL;
> +     INIT_LIST_HEAD(&drv->node);
> +     INIT_LIST_HEAD(&drv->raw_devices);
> +     drv->flags = 0;
> +     return 0;
> +}
> +
> +static void inline hidinput_simple_configure_one_usage(int op, 
> +                                             struct input_dev *input,
> +                                             struct hid_usage *usage,
> +                                             struct usage_block *usage_block)
> +{
> +     unsigned long *bits;
> +     int flag;
> +     struct hid_device *hid;
> +
> +     hid = input->private;
> +     switch (usage_block->event) {
> +     case EV_KEY:
> +             flag = HIDINPUT_SIMPLE_KEYBIT;
> +             bits = input->keybit;
> +             break;
> +     case EV_REL:
> +             flag = HIDINPUT_SIMPLE_RELBIT;
> +             bits = input->relbit;
> +             break;
> +     case EV_ABS:
> +             flag = HIDINPUT_SIMPLE_ABSBIT;
> +             bits = input->relbit;
> +             break;
> +     case EV_MSC:
> +             flag = HIDINPUT_SIMPLE_MSCBIT;
> +             bits = input->absbit;
> +             break;
> +     case EV_SW:
> +             flag = HIDINPUT_SIMPLE_SWBIT;
> +             bits = input->swbit;
> +             break;
> +     case EV_LED:
> +             flag = HIDINPUT_SIMPLE_LEDBIT;
> +             bits = input->ledbit;
> +             break;
> +     case EV_SND:
> +             flag = HIDINPUT_SIMPLE_SNDBIT;
> +             bits = input->sndbit;
> +             break;
> +     case EV_FF:
> +             flag = HIDINPUT_SIMPLE_FFBIT;
> +             bits = input->ffbit;
> +             break;
> +     case EV_FF_STATUS:
> +             flag = HIDINPUT_SIMPLE_FFSTSBIT;
> +             bits = NULL;
> +             break;
> +     default:
> +             return;
> +     }
> +
> +     if (__OP_SET_BIT == op) {
> +             usage->code = usage_block->code;
> +             usage->type = usage_block->event;
> +             if (bits)
> +                     set_bit(usage_block->code, bits);
> +             /* if this event bit is set by us first, remember it */
> +             if (!test_and_set_bit(usage_block->event, input->evbit))
> +                     set_bit(flag, &hid->simple->flags);
> +     }
> +     else if (__OP_CLR_BIT == op) {
> +             usage->code = 0;
> +             usage->type = 0;
> +             if (bits)
> +                     clear_bit(usage_block->code, bits);
> +             /* clear event bit, only if it's set by us. */
> +             if (test_and_clear_bit(flag, &hid->simple->flags))
> +                     clear_bit(usage_block->event, input->evbit);
> +     }
> +}
> +
> +static do_usage_t hidinput_simple_driver_configure_usage_prep(
> +                                                     struct hid_device *hid,
> +                                                     int *op)
> +{
> +     do_usage_t do_usage;
> +
> +     if (!hid->simple)
> +             return NULL;
> +
> +     if (test_bit(HIDINPUT_SIMPLE_SETUP_USAGE, &hid->simple->flags)) {
> +             do_usage = hid->simple->setup_usage;
> +             *op = __OP_SET_BIT;
> +     }
> +     else {
> +             do_usage = hid->simple->clear_usage;
> +             *op = __OP_CLR_BIT;
> +     }
> +     return do_usage;
> +}
> +
> +static void __hidinput_simple_driver_configure_usage(int op,
> +                                             struct hid_field *field,
> +                                             struct hid_usage *hid_usage)
> +{
> +     struct input_dev *input = field->hidinput->input;
> +     struct hid_device *hid = input->private;
> +     struct usage_block *usage_block;
> +     struct usage_page_block *page_block;
> +     int page;
> +     int usage;
> +
> +     page = (hid_usage->hid & HID_USAGE_PAGE);
> +     usage = (hid_usage->hid & HID_USAGE);
> +     page_block = hid->simple->usage_page_table;
> +     for (;page_block && page_block->usage_blockes;page_block++) {
> +             if (page_block->page != page)
> +                     continue;
> +             usage_block = page_block->usage_blockes;
> +             for (; usage_block && usage_block->usage; usage_block++) {
> +                     if (usage_block->usage != usage)
> +                             continue;
> +                     hidinput_simple_configure_one_usage(op, input, 
> +                                             hid_usage, usage_block);
> +             }
> +     }
> +}
> +
> +/*
> + *  To give one simple device a configure usage chance.
> + *  The framework of this function come from hidinput_connect()
> + */
> +void hidinput_simple_driver_configure_usage(struct hid_device *hid)
> +{
> +     struct hid_report *report;
> +     int i, j, k;
> +     do_usage_t do_usage;
> +     int op;
> +
> +     if (!hid->simple)
> +             return;
> +     do_usage = hidinput_simple_driver_configure_usage_prep(hid, &op);
> +
> +     for (i = 0; i < hid->maxcollection; i++)
> +             if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
> +                     hid->collection[i].type==HID_COLLECTION_PHYSICAL)
> +                     if (IS_INPUT_APPLICATION(hid->collection[i].usage))
> +                             break;
> +
> +     if (i == hid->maxcollection)
> +             return;
> +
> +     for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
> +             list_for_each_entry(report, &hid->report_enum[k].report_list, 
> list) {
> +                     if (!report->maxfield)
> +                             continue;
> +
> +                     for (i = 0; i < report->maxfield; i++)
> +                             for (j = 0; j < report->field[i]->maxusage; 
> j++) {
> +                                     
> __hidinput_simple_driver_configure_usage(op, report->field[i], 
> report->field[i]->usage + j);
> +                                     if (do_usage)
> +                                             do_usage(report->field[i],
> +                                             report->field[i]->usage + j);
> +                             }
> +             }
> +
> +     return;
> +}
> +
> +int hidinput_simple_driver_push(struct hid_device *hid, 
> +                                     struct hidinput_simple_driver *simple,
> +                                     struct matched_device *matched)
> +{
> +     struct raw_simple_device *raw_simple;
> +
> +     raw_simple = kmalloc(sizeof(struct raw_simple_device), GFP_KERNEL);
> +     if (!raw_simple)
> +             return -ENOMEM;
> +     raw_simple->intf = matched->intf;
> +     hid = usb_get_intfdata(matched->intf);
> +     hid->simple = simple;
> +     list_add(&raw_simple->node, &simple->raw_devices);
> +     return 0;
> +}
> +
> +void hidinput_simple_driver_pop(struct hid_device *hid,
> +                                     struct matched_device *matched)
> +{
> +     struct list_head *node;
> +     struct raw_simple_device *raw_simple=NULL;
> +
> +     list_for_each (node, &hid->simple->raw_devices) {
> +             raw_simple = list_entry(node, struct raw_simple_device, node);
> +             if (raw_simple && raw_simple->intf == matched->intf) {
> +                     hid->simple = NULL;
> +                     list_del(&raw_simple->node);
> +                     kfree(raw_simple);
> +                     return;
> +             }
> +     }
> +}
> +
> +void hidinput_simple_driver_clear(struct hidinput_simple_driver *simple)
> +{
> +     struct raw_simple_device *raw_simple;
> +     struct hid_device *hid;
> +
> +     while (!list_empty_careful(&simple->raw_devices)) {
> +             raw_simple = list_entry(simple->raw_devices.next, 
> +                                     struct raw_simple_device, node);
> +             hid = usb_get_intfdata (raw_simple->intf);
> +             if (hid) {
> +                     if (hid->simple)
> +                             BUG_ON(hid->simple != simple);
> +                     hidinput_simple_driver_clear_usage(hid);
> +                     wmb();
> +                     hidinput_simple_driver_disconnect(hid);
> +                     hid->simple = NULL;
> +             }
> +             list_del_init(simple->raw_devices.next);
> +     }
> +}
> +
> +int hidinput_simple_driver_connect(struct hidinput_simple_driver *simple, 
> +                                             struct hid_device *hid)
> +{
> +     struct hid_input *hidinput, *next;
> +     int ret = -ENODEV;
> +
> +     if (!simple)
> +             goto exit;
> +     if (!simple->connect) {
> +             ret = 0;
> +             goto exit;
> +     }
> +
> +     list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
> +             if (!simple->connect(hid, hidinput)) {
> +                     hid->simple = simple;
> +                     ret = 0;
> +             }
> +     }
> +exit:
> +     set_bit(HIDINPUT_SIMPLE_CONNECTED, &simple->flags);
> +     return ret;
> +}
> +
> +
> +void hidinput_simple_driver_disconnect(struct hid_device *hid)
> +{
> +     struct hid_input *hidinput, *next;
> +
> +     if (!hid || !hid->simple)
> +             return;
> +
> +     if (!hid->simple->disconnect)
> +             goto exit;
> +     list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
> +             hid->simple->disconnect(hid, hidinput);
> +     }
> +exit:
> +     clear_bit(HIDINPUT_SIMPLE_CONNECTED, &hid->simple->flags);
> +     return;
> +}
> +
> +struct hid_input* hidinput_simple_inputdev_to_hidinput(struct input_dev *dev)
> +{
> +     struct hid_device *hid = dev->private;
> +     struct list_head *iter;
> +     struct hid_input *hidinput;
> +
> +     list_for_each(iter, &hid->inputs) {
> +             hidinput = list_entry(iter, struct hid_input, list);
> +             if (hidinput->input == dev)
> +                     return hidinput;
> +     }
> +     return NULL;
> +}
> +EXPORT_SYMBOL_GPL(hidinput_simple_inputdev_to_hidinput);
> diff -Naurp linux-2.6.18/drivers/usb/input/hid-simple.h 
> linux-2.6.18/drivers/usb/input.new/hid-simple.h
> --- linux-2.6.18/drivers/usb/input/hid-simple.h       1970-01-01 
> 08:00:00.000000000 +0800
> +++ linux-2.6.18/drivers/usb/input.new/hid-simple.h   2006-09-28 
> 09:28:15.000000000 +0800
> @@ -0,0 +1,232 @@
> +/*
> + *  NOTE:
> + *   For use me , you must include hid.h in your source first. 
> + */
> +#ifndef __HID_SIMPLE_H
> +#define __HID_SIMPLE_H
> +
> +#ifdef __KERNEL__
> +
> +#include <linux/usb.h>
> +
> +/***** The public interface for simple device driver *****/
> +struct usage_block {
> +     int usage; /* usage code */
> +     int value; /* not used, for F_EVENT_BY_VALUE in future  */
> +     int event; /* input event type, e.g. EV_KEY. */
> +     int code;  /* input subsystem code, e.g. KEY_F1. */
> +     int flags; /* not used */
> +};
> +
> +struct usage_page_block {
> +     int page; /* usage page code */
> +     int flags; /* not used */
> +     struct usage_block *usage_blockes;
> +};
> +
> +/* usage_block flags list */
> +#define F_EVENT_BY_VALUE (0x1) /* submit input event by usage_block.value, 
> +                               not implement yet */
> +
> +#define USAGE_BLOCK(i_usage, i_value, i_event, i_code, i_flags) \
> +     {\
> +             .usage = (i_usage),\
> +             .value = (i_value),\
> +             .event = (i_event),\
> +             .code = (i_code),\
> +             .flags = (i_flags),\
> +     }
> +
> +#define USAGE_BLOCK_NULL {}
> +
> +#define USAGE_PAGE_BLOCK(i_page, i_usage_blockes) \
> +     {\
> +             .page = (i_page),\
> +             .usage_blockes = (i_usage_blockes),\
> +     }
> +
> +#define USAGE_PAGE_BLOCK_NULL {}
> +
> +#define __SIMPLE_DRIVER_INIT \
> +     .owner = THIS_MODULE,
> +
> +struct hidinput_simple_driver {
> +/* private */
> +     struct list_head node; /* link with simple_drivers_list */
> +     struct list_head raw_devices;
> +     unsigned long flags;
> +/* public */
> +     struct module *owner;
> +     char *name;
> +     int (*connect)(struct hid_device *, struct hid_input *);        
> +     void (*disconnect)(struct hid_device *, struct hid_input *);
> +     void (*setup_usage)(struct hid_field *,   struct hid_usage *);
> +     void (*clear_usage)(struct hid_field *,   struct hid_usage *);
> +     int (*pre_event)(const struct hid_device *, const struct hid_field *,
> +                                     const struct hid_usage *, const __s32,
> +                                     const struct pt_regs *regs);
> +     int (*post_event)(const struct hid_device *, const struct hid_field *,
> +                                     const struct hid_usage *, const __s32,
> +                                     const struct pt_regs *regs);
> +     int (*open)(struct input_dev *dev);
> +     void (*close)(struct input_dev *dev);
> +        int (*upload_effect)(struct input_dev *dev, struct ff_effect 
> *effect);
> +        int (*erase_effect)(struct input_dev *dev, int effect_id);
> +     int (*flush)(struct input_dev *dev, struct file *file);
> +     int (*ff_event)(struct input_dev *dev, int type, int code, int value);
> +     struct usb_device_id *id_table;
> +     struct usage_page_block *usage_page_table;
> +     void *private;
> +};
> +
> +
> +int hidinput_register_simple_driver(struct hidinput_simple_driver *device);
> +void hidinput_unregister_simple_driver(struct hidinput_simple_driver 
> *device);
> +struct hid_input* hidinput_simple_inputdev_to_hidinput(struct input_dev 
> *dev);
> +
> +/********************* The public section end ***********/
> +
> +/***** The private section for simple device driver implement only *****/
> +
> +/* simple driver internal flags */
> +#define HIDINPUT_SIMPLE_SETUP_USAGE  (0x0)
> +#define HIDINPUT_SIMPLE_KEYBIT       (0x1)
> +#define HIDINPUT_SIMPLE_RELBIT       (0x2)
> +#define HIDINPUT_SIMPLE_ABSBIT       (0x3)
> +#define HIDINPUT_SIMPLE_MSCBIT       (0x4)
> +#define HIDINPUT_SIMPLE_SWBIT        (0x5)
> +#define HIDINPUT_SIMPLE_LEDBIT       (0x6)
> +#define HIDINPUT_SIMPLE_SNDBIT       (0x7)
> +#define HIDINPUT_SIMPLE_FFBIT        (0x8)
> +#define HIDINPUT_SIMPLE_FFSTSBIT     (0x9)
> +#define HIDINPUT_SIMPLE_CONNECTED    (0x1f)
> +
> +/* used in hidinput_simple_driver_configure_usage() */
> +#define __OP_SET_BIT (1)
> +#define __OP_CLR_BIT (0)
> +
> +/* 
> + *  matched_device record one device which hid-subsystem handle, it may 
> + *  be one simple device can not handle.
> + *
> + *  The element of matched_device list is inserted at hidinput_connect(), 
> + *  and is removed  at hidinput_disconnect().
> + */ 
> +struct matched_device {
> +     struct usb_interface *intf;
> +     struct list_head node;
> +};
> +
> +/* 
> + *  raw_simple_driver record one device which hid simple device handle.
> + *  It used as one member of hid_simple_driver.
> + */ 
> +
> +struct raw_simple_device {
> +     struct usb_interface *intf;
> +     struct list_head node;
> +};
> +
> +#ifdef CONFIG_HID_SIMPLE
> +extern void hidinput_simple_driver_configure_usage(struct hid_device *hid);
> +extern int hidinput_simple_driver_init(struct hidinput_simple_driver 
> *simple);
> +extern int hidinput_simple_driver_push(struct hid_device *hid,
> +                             struct hidinput_simple_driver *simple,
> +                             struct matched_device *dev);
> +extern void hidinput_simple_driver_pop(struct hid_device *hid,
> +                             struct matched_device *dev);
> +extern void hidinput_simple_driver_clear(struct hidinput_simple_driver 
> *simple);
> +extern int hidinput_simple_driver_connect(struct hidinput_simple_driver 
> *simple, 
> +                                                     struct hid_device *hid);
> +extern void hidinput_simple_driver_disconnect(struct hid_device *hid);
> +static void inline hidinput_simple_driver_setup_usage(struct hid_device *hid)
> +{
> +     if (hid && hid->simple) {
> +             set_bit(HIDINPUT_SIMPLE_SETUP_USAGE, &hid->simple->flags);
> +             hidinput_simple_driver_configure_usage(hid);
> +     }
> +}
> +
> +static void inline hidinput_simple_driver_clear_usage(struct hid_device *hid)
> +{
> +     if (hid && hid->simple) {
> +             clear_bit(HIDINPUT_SIMPLE_SETUP_USAGE, &hid->simple->flags);
> +             hidinput_simple_driver_configure_usage(hid);
> +     }
> +}
> +
> +#ifdef CONFIG_HID_SIMPLE_FF
> +static inline int hidinput_upload_effect(struct input_dev *dev,
> +                                             struct ff_effect *effect)
> +{
> +     struct hid_device *hid;
> +
> +     hid = dev->private;
> +     if (hid->simple && hid->simple->upload_effect)
> +             return hid->simple->upload_effect(dev, effect);
> +     return 0;
> +}
> +
> +static inline int hidinput_erase_effect(struct input_dev *dev, int effect_id)
> +{
> +     struct hid_device *hid;
> +
> +     hid = dev->private;
> +     if (hid->simple && hid->simple->erase_effect)
> +             return hid->simple->erase_effect(dev, effect_id);
> +     return 0;
> +}
> +
> +static inline int hidinput_flush(struct input_dev *dev, struct file *filep)
> +{
> +     struct hid_device *hid;
> +
> +     hid = dev->private;
> +     if (hid->simple && hid->simple->flush)
> +             return hid->simple->flush(dev, filep);
> +     return 0;
> +}
> +
> +static void inline hidinput_simple_driver_ff_init(struct input_dev 
> *input_dev)
> +{
> +     input_dev->upload_effect = hidinput_upload_effect;
> +     input_dev->erase_effect = hidinput_erase_effect;
> +     input_dev->flush = hidinput_flush;
> +}
> +#else /* CONFIG_HID_SIMPLE_FF */
> +static void inline hidinput_simple_driver_ff_init(struct input_dev 
> *input_dev) {}
> +#endif /* CONFIG_HID_SIMPLE_FF */
> +#else /* CONFIG_HID_SIMPLE */
> +static inline void hidinput_simple_driver_bind_foreach_simple(
> +                                     struct matched_device *matched) {}
> +static inline void hidinput_simple_driver_configure_usage(struct hid_device 
> *hid)
> +{}
> +static inline int hidinput_simple_driver_init(struct hidinput_simple_driver 
> *simple)
> +{
> +     return 0;
> +}
> +static inline int hidinput_simple_driver_push(struct hid_device *hid,
> +                             struct hidinput_simple_driver *simple,
> +                             struct matched_device *dev)
> +{
> +     return 0;
> +}
> +static inline void hidinput_simple_driver_pop(struct hid_device *hid,
> +                             struct matched_device *dev) {}
> +static inline void hidinput_simple_driver_clear(
> +                             struct hidinput_simple_driver *simple) {}
> +static inline int hidinput_simple_driver_connect(
> +                             struct hidinput_simple_driver *simple, 
> +                             struct hid_device *hid)
> +{
> +     return 0;
> +}
> +static inline void hidinput_simple_driver_disconnect(struct hid_device *hid) 
> {}
> +static inline void hidinput_simple_driver_setup_usage(struct hid_device 
> *hid) {}
> +static inline void hidinput_simple_driver_clear_usage(struct hid_device 
> *hid) {}
> +static void inline hidinput_simple_driver_ff_init(struct input_dev 
> *input_dev) {}
> +#endif
> +
> +/***** The private section end.  *****/
> +#endif /* __KERNEL__ */
> +#endif /* __HID_SIMPLE_H */
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [EMAIL PROTECTED]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 


---
~Randy

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to