diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-al.c 
linux-2.6.21-rc6-mm1.new/drivers/hid/hid-al.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-al.c      1970-01-01 
08:00:00.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/hid-al.c       2007-04-15 
21:34:44.000000000 +0800
@@ -0,0 +1,505 @@
+/*
+ *  HID abstract layer for Linux driver model
+ *
+ *  Copyright (c) 2007 Li Yu
+ */
+
+/*
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/wait.h>
+
+#include "hid-inter.h"
+
+static spinlock_t hid_lock;
+
+struct hid_transport* hid_transports[BUS_MAX];
+static unsigned long hid_transports_exiting[BUS_MAX];
+#define set_hid_transport_exiting(tl)  (set_bit(1, 
hid_transports_exiting+(tl)->bus))
+#define is_hid_transport_exiting(tl)   (test_bit(1, 
hid_transports_exiting+(tl)->bus))
+#define clear_hid_transport_exiting(tl)        (clear_bit(1, 
hid_transports_exiting+(tl)->bus))
+EXPORT_SYMBOL(hid_transports);
+
+
+struct hid_driver* hid_sticky_drivers[NR_STICKY];
+static DECLARE_WAIT_QUEUE_HEAD(hid_sticky_clean_barrier);
+static unsigned long hid_sticky_exiting[NR_STICKY];
+#define set_hid_sticky_exiting(i)      (set_bit(1, hid_sticky_exiting+i))
+#define is_hid_sticky_exiting(i)       (test_bit(1, hid_sticky_exiting+i))
+#define clear_hid_sticky_exiting(i)    (clear_bit(1, hid_sticky_exiting+i))
+
+static int hid_sticky_get(struct hid_driver *hid_drv)
+{
+       return try_module_get(hid_drv->module);
+}
+
+static void hid_sticky_put(struct hid_driver *hid_drv)
+{
+       module_put(hid_drv->module);
+       if(!module_refcount(hid_drv->module))
+               wake_up(&hid_sticky_clean_barrier);
+}
+
+int hid_sticky_driver_exit(int i)
+{
+       if (is_hid_sticky_exiting(i)) {
+               hid_sticky_put(hid_sticky_drivers[i]);
+               return 1;
+       }
+       return 0;
+}
+
+static int hid_driver_skip_device_helper(struct device *dev, void *data)
+{
+       struct skip_id *skip = data;
+       int mask = skip->mask;
+       struct hid_device *hid_dev = to_hid_device(dev);
+       
+       if ((mask & HID_IGNORE_VENDOR) &&
+                               (hid_dev->vendor != skip->vendor))
+               return 0;
+       if ((mask & HID_IGNORE_PRODUCT) && 
+                               (hid_dev->product != skip->product))
+               return 0;
+       if ((mask & HID_IGNORE_VERSION) && 
+                               (hid_dev->version != skip->version))
+               return 0;
+       if ((mask & HID_IGNORE_COUNTRY) &&
+                               (hid_dev->country != skip->country))
+               return 0;
+
+       return 1;
+}
+
+static int hid_driver_match_skip_table(struct hid_driver *hid_drv,
+                                               struct hid_device *hid_dev)
+{
+       struct skip_id *skip;
+
+       list_for_each_entry(skip, &hid_drv->skip_table, node) {
+               if (hid_driver_skip_device_helper(&hid_dev->device, skip))
+                       return 1;
+       }
+       return 0;
+}
+static int hid_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct hid_driver *hid_drv;
+       struct hid_device *hid_dev;
+       
+       hid_drv = to_hid_driver(drv);
+       hid_dev = to_hid_device(dev);
+
+       if (is_hid_driver_sticky(hid_drv))
+               /* the sticky driver match device do not pass here. */
+               return 0;
+       if (hid_dev->bus != hid_drv->bus)
+               return 0;
+       if (hid_driver_match_skip_table(hid_drv, hid_dev))
+               return 0;
+       if (!hid_drv->match || hid_drv->match(hid_drv, hid_dev)) {
+               hid_dev->driver = hid_drv;
+               return 1;
+       }
+       return 0;
+}
+
+static ssize_t hid_driver_show_version(struct device_driver *drv, char *buf)
+{
+       struct hid_driver *hid_drv;
+
+       hid_drv = to_hid_driver(drv);
+       return snprintf(buf, PAGE_SIZE, "%s\n", hid_drv->version);
+}
+
+static ssize_t hid_driver_show_sticky(struct device_driver *drv, char *buf)
+{
+       struct hid_driver *hid_drv;
+
+       hid_drv = to_hid_driver(drv);
+       return snprintf(buf, PAGE_SIZE, "%d\n", is_hid_driver_sticky(hid_drv));
+}
+
+static ssize_t hid_driver_show_skip(struct device_driver *drv, char *buf)
+{
+       /* FIXME: we really need this? */
+       return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static void hid_driver_skip_device(struct hid_driver *hid_drv,
+                                       struct skip_id *skip)
+{
+       struct device *dev;
+       
+       do {
+               dev = driver_find_device(&hid_drv->driver, NULL,
+                               skip, hid_driver_skip_device_helper);
+               if (!dev)
+                       return;
+               device_release_driver(dev);
+       } while (1);
+}
+
+static ssize_t hid_driver_store_skip(struct device_driver *drv,
+                                               const char *buf, size_t count)
+{
+       struct hid_driver *hid_drv;
+       int vendor = 0, product = 0, version = 0, country = 0, mask = 0;
+       struct skip_id *skip;
+       int n;
+       
+       hid_drv = to_hid_driver(drv);
+       n = sscanf(buf, "skip:0x%x,0x%x,0x%x,0x%x,0x%x\n",
+               &vendor, &product, &version, &country, &mask);
+       if (n<2)
+               return -EINVAL;
+       skip = kzalloc(sizeof(struct skip_id), GFP_KERNEL);
+       if (!skip)
+               return -ENOMEM;
+       if (!mask)
+               mask = HID_IGNORE_VENDOR|HID_IGNORE_PRODUCT;
+       skip->vendor = vendor;
+       skip->product = product;
+       skip->version = version;
+       skip->country = country;
+       skip->mask = mask;
+       spin_lock(&hid_lock);
+       list_add_tail(&skip->node, &hid_drv->skip_table);
+       spin_unlock(&hid_lock);
+       hid_driver_skip_device(hid_drv, skip);
+       return count;
+}
+
+static struct driver_attribute hidbus_driver_attrs[] = {
+       __ATTR(version, 0444, hid_driver_show_version, NULL),
+       __ATTR(sticky, 0444, hid_driver_show_sticky, NULL),
+       __ATTR(skip_id, 0644, hid_driver_show_skip, hid_driver_store_skip),
+       __ATTR_NULL
+};
+
+struct bus_type hid_bus_type = {
+       .name = "hid",
+       .match = hid_bus_match,
+       .drv_attrs = hidbus_driver_attrs,
+};
+
+static void hid_dummy_release(struct device *dev)
+{
+}
+
+struct device hid_bus = {
+       .bus_id = "hidbus0",
+       .release = hid_dummy_release
+};
+
+static void hid_device_create_links(struct hid_device *hid_dev)
+{
+       struct hid_input *hidinput;
+       int ret;
+       
+       list_for_each_entry(hidinput, &hid_dev->inputs, list)
+               ret = sysfs_create_link(&hid_dev->device.kobj,
+                                       &hidinput->input->dev.kobj,
+                                       hidinput->input->dev.bus_id);
+       ret = sysfs_create_link(&hid_dev->device.kobj,
+                               &hid_dev->dev->kobj, "transport_device");
+}
+
+static void hid_device_remove_links(struct hid_device *hid_dev)
+{
+       struct hid_input *hidinput;
+       
+       list_for_each_entry(hidinput, &hid_dev->inputs, list)
+               sysfs_remove_link(&hid_dev->device.kobj,
+                                       hidinput->input->dev.bus_id);
+
+       sysfs_remove_link(&hid_dev->device.kobj, "transport_device");
+}
+
+static int hid_drv_probe(struct device *dev)
+{
+       struct hid_device *hid_dev;
+       struct hid_driver *hid_drv;
+       struct hid_transport *tl;
+       int i;
+       
+       hid_dev = to_hid_device(dev);
+       hid_drv = hid_dev->driver;
+       tl = hid_transports[hid_dev->bus];
+       
+       if (is_hid_transport_exiting(tl))
+               return -ENODEV;
+       if (!try_module_get(tl->module))
+               return -ENODEV;
+
+       if (!hid_drv->probe)
+               if (!hidinput_connect(hid_dev))
+                       goto ok;
+       if (hid_drv->probe(hid_dev)) {
+               hid_dev->driver = NULL;
+               return -ENODEV;
+       }
+ok:
+       for (i=0; i<NR_STICKY; ++i) {
+               hid_drv = hid_sticky_drivers[i];
+               if (!hid_drv || is_hid_sticky_exiting(i))
+                       continue;
+               if (!hid_sticky_get(hid_drv))
+                       continue;
+               if (!try_module_get(tl->module)) {
+                       hid_sticky_put(hid_drv);
+                       continue;
+               }
+               if (!hid_drv->probe)
+                       set_bit(i, &hid_dev->sticky_driver);
+               else if (!hid_drv->probe(hid_dev))
+                       set_bit(i, &hid_dev->sticky_driver);
+               else {
+                       clear_bit(i, &hid_dev->sticky_driver);
+                       hid_sticky_put(hid_drv);
+                       module_put(tl->module);
+               }
+       }
+       hid_device_create_links(hid_dev);
+       return 0;
+}
+
+static int hid_drv_remove(struct device *dev)
+{
+       struct hid_device *hid_dev;
+       struct hid_driver *hid_drv;
+       struct hid_transport *tl;
+       int i;
+       
+       hid_dev = to_hid_device(dev);
+       hid_drv = hid_dev->driver;
+       tl = hid_transports[hid_dev->bus];
+       
+       hid_device_remove_links(hid_dev);
+       module_put(tl->module);
+       if (!hid_drv->remove)
+               hidinput_disconnect(hid_dev);
+       else
+               hid_drv->remove(hid_dev);
+               
+       for (i=0; i<NR_STICKY; ++i) {
+               hid_drv = hid_sticky_drivers[i];
+               if (!hid_drv)
+                       continue;
+               if (hid_drv->remove)
+                       hid_drv->remove(hid_dev);
+               clear_bit(i, &hid_dev->sticky_driver);
+               hid_sticky_put(hid_drv);
+               module_put(tl->module);
+       }
+       return 0;
+}
+
+static void hid_drv_shutdown(struct device *dev)
+{
+       struct hid_device *hid_dev;
+
+       hid_dev = to_hid_device(dev);
+       
+       if (!hid_dev->driver);
+               return;
+       if (hid_dev->driver->shutdown)
+               hid_dev->driver->shutdown(hid_dev);
+}
+
+static inline int hid_check_transport(int bus)
+{
+       if (bus<=0 || bus>=BUS_MAX)
+               return 0;
+       
+       return (int)hid_transports[bus];
+}
+
+static int match_device_for_transport(struct device *dev, void *bus)
+{
+       struct hid_device *hid_dev = to_hid_device(dev);
+       
+       if (hid_dev->bus != (int)bus)
+               return 0;
+       device_release_driver(dev);
+       return 0;
+}
+
+static void unbind_devices_for_transport(int bus)
+{
+       struct device *dev;
+       
+restart:
+       dev = bus_find_device(&hid_bus_type, NULL,
+                               (void*)bus, match_device_for_transport);
+       if (!dev)
+               return;
+       goto restart;
+}
+
+int hid_register_device(struct hid_device *hid_dev)
+{
+       if (!hid_dev || !hid_check_transport(hid_dev->bus))
+               return -EINVAL;
+               
+       hid_dev->device.bus = &hid_bus_type;
+       hid_dev->device.release = hid_dummy_release;
+       hid_dev->device.parent = &hid_bus;
+       INIT_LIST_HEAD(&hid_dev->inputs);
+       hid_transports[hid_dev->bus]->update_busid(hid_dev);
+       return device_register(&hid_dev->device);
+}
+EXPORT_SYMBOL_GPL(hid_register_device);
+
+void hid_unregister_device(struct hid_device *hid_dev)
+{
+       device_unregister(&hid_dev->device);
+}
+EXPORT_SYMBOL_GPL(hid_unregister_device);
+
+int hid_register_driver(struct hid_driver *hid_drv)
+{
+       int ret, i;
+       
+       if (!hid_drv)
+               return -EINVAL;
+       if (!hid_check_transport(hid_drv->bus))
+               return -EINVAL;
+       if (!try_module_get(hid_drv->module))
+               return -EINVAL;
+       hid_drv->driver.bus = &hid_bus_type;
+       hid_drv->driver.name = hid_drv->name;
+       hid_drv->driver.probe = hid_drv_probe;
+       hid_drv->driver.remove = hid_drv_remove;
+       hid_drv->driver.shutdown = hid_drv_shutdown;
+       INIT_LIST_HEAD(&hid_drv->skip_table);
+       ret = driver_register(&hid_drv->driver);
+       if (!is_hid_driver_sticky(hid_drv))
+               return ret;
+       spin_lock(&hid_lock);
+       for (i=0; i<NR_STICKY; ++i) {
+               if (!hid_sticky_drivers[i]) {
+                       clear_hid_sticky_exiting(i);
+                       hid_sticky_drivers[i] = hid_drv;
+                       break;
+               }
+       }
+       spin_unlock(&hid_lock);
+       if (i<NR_STICKY)
+               return 0;
+       module_put(hid_drv->module);
+       driver_unregister(&hid_drv->driver);
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(hid_register_driver);
+
+void hid_unregister_driver(struct hid_driver *hid_drv)
+{
+       struct skip_id *skip, *next;
+       int i;
+       
+       if (!is_hid_driver_sticky(hid_drv))
+               goto skip_sticky;
+       for (i=0; i<NR_STICKY; ++i)
+               if (hid_drv == hid_sticky_drivers[i]) {
+                       set_hid_sticky_exiting(i);
+                       break;
+               }
+       if (i>=NR_STICKY)
+               return;
+       module_put(hid_drv->module);
+       wait_event(hid_sticky_clean_barrier, !module_refcount(hid_drv->module));
+       spin_lock(&hid_lock);
+       hid_sticky_drivers[i] = NULL;
+       spin_unlock(&hid_lock);
+
+skip_sticky:
+       driver_unregister(&hid_drv->driver);
+       list_for_each_entry_safe(skip, next, &hid_drv->skip_table, node) {
+               list_del(&skip->node);
+               kfree(skip);
+       }
+}
+EXPORT_SYMBOL_GPL(hid_unregister_driver);
+
+int hid_register_transport(struct hid_transport *tl)
+{
+       int ret;
+
+       if (!tl || tl->bus>=BUS_MAX || tl->bus<=0)
+               return -EINVAL;
+       if (!try_module_get(tl->module))
+               return -EINVAL;
+       ret = 0;
+       spin_lock(&hid_lock);
+       if (!hid_transports[tl->bus]) {
+               hid_transports[tl->bus] = tl;
+               clear_hid_transport_exiting(tl);
+       }
+       else
+               ret = -EBUSY;
+       spin_unlock(&hid_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hid_register_transport);
+
+void hid_unregister_transport(struct hid_transport *tl)
+{
+       if (!tl || tl->bus>=BUS_MAX || tl->bus<=0 || tl != 
hid_transports[tl->bus])
+               return;
+       set_hid_transport_exiting(tl);
+       module_put(tl->module);
+       unbind_devices_for_transport(tl->bus);
+       spin_lock(&hid_lock);
+       hid_transports[tl->bus] = NULL;
+       spin_unlock(&hid_lock);
+       return;
+}
+EXPORT_SYMBOL_GPL(hid_unregister_transport);
+
+static ssize_t hid_bus_show_version(struct bus_type *bus, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0.1.0\n");
+}
+
+BUS_ATTR(version, 0444, hid_bus_show_version, NULL);
+
+static int __init hid_init(void)
+{
+       int ret;
+       
+       spin_lock_init(&hid_lock);
+       ret = device_register(&hid_bus);
+       if (ret)
+               return ret;
+       ret = bus_register(&hid_bus_type);
+       if (ret) {
+               device_unregister(&hid_bus);
+               return ret;
+       }
+       ret = bus_create_file(&hid_bus_type, &bus_attr_version);
+       return 0;
+}
+
+static void __exit hid_exit(void)
+{
+       bus_remove_file(&hid_bus_type, &bus_attr_version);
+       device_unregister(&hid_bus);
+       bus_unregister(&hid_bus_type);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-core.c 
linux-2.6.21-rc6-mm1.new/drivers/hid/hid-core.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-core.c    2007-04-10 
09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/hid-core.c     2007-04-11 
09:12:02.000000000 +0800
@@ -28,9 +28,8 @@
 #include <linux/vmalloc.h>
 
 #include <linux/hid.h>
-#include <linux/hiddev.h>
 #include <linux/hid-debug.h>
-#include <linux/hidraw.h>
+#include "hid-inter.h"
 
 /*
  * Version Information
@@ -39,7 +38,6 @@
 #define DRIVER_VERSION "v2.6"
 #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
 #define DRIVER_DESC "HID core driver"
-#define DRIVER_LICENSE "GPL"
 
 /*
  * Register a new report for a device.
@@ -634,7 +632,7 @@ struct hid_device *hid_parse_report(__u8
                hid_parser_reserved
        };
 
-       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
+       if (!(device = hid_new_device(GFP_KERNEL)))
                return NULL;
 
        if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
@@ -802,11 +800,17 @@ 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 hid_hook *hook;
+
+       if (!hid->driver)
+               return;
+               
+       hook = hid->driver->hook;       
        hid_dump_input(usage, value);
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_hid_event(hid, field, usage, value);
-       if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && 
hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
+       if (hook && hook->hid_event && 
+                       !hook->hid_event(field, usage, value, interrupt))
+               return;
+       hidinput_hid_event(hid, field, usage, value);
 }
 
 /*
@@ -825,11 +829,13 @@ void hid_input_field(struct hid_device *
        __s32 max = field->logical_maximum;
        __s32 *value;
 
+       if (!hid->driver)
+               return;
+
        if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
                return;
 
        for (n = 0; n < count; n++) {
-
                        value[n] = min < 0 ? snto32(extract(data, offset + n * 
size, size), size) :
                                                    extract(data, offset + n * 
size, size);
 
@@ -931,14 +937,110 @@ int hid_set_field(struct hid_field *fiel
 }
 EXPORT_SYMBOL_GPL(hid_set_field);
 
+static int hid_raw_event(struct hid_device *hid, int type, u8 *data,
+                                                       int size, int interrupt)
+{
+       struct hid_hook *hook;
+       int ret, i;
+       
+       if (!hid->driver)
+               return 0;
+
+       hook = hid->driver->hook;
+       if (hook && hook->raw_event) {
+               if (!hook->raw_event(hid, type, data, size, interrupt))
+                       return 0;
+       }
+       
+       ret = -ENODEV;
+       for (i=0; i<NR_STICKY; ++i) {
+               if (!hid_sticky_drivers[i] || !test_bit(i, &hid->sticky_driver))
+                       continue;
+               if (hid_sticky_driver_exit(i)) {
+                       clear_bit(i, &hid->sticky_driver);
+                       continue;
+               }
+               hook = hid_sticky_drivers[i]->hook;
+               if (hook && hook->raw_event) {
+                       ret = hook->raw_event(hid, type, data, size, interrupt);
+                       if (!ret)
+                               break;
+               }
+       }
+       return ret;
+}
+
+static int hid_report_pre_event(struct hid_device *hid,
+                                       struct hid_report *report, int 
interrupt)
+{
+       struct hid_hook *hook;
+       int ret, i;
+
+       if (!hid->driver)
+               return 0;
+
+       hook = hid->driver->hook;
+       if (hook && hook->pre_report_event) {
+               if (!hook->pre_report_event(report, interrupt))
+                       return 0;
+       }
+
+       ret = -ENODEV;
+       for (i=0; i<NR_STICKY; ++i) {
+               if (!hid_sticky_drivers[i] || !test_bit(i, &hid->sticky_driver))
+                       continue;
+               if (hid_sticky_driver_exit(i)) {
+                       clear_bit(i, &hid->sticky_driver);
+                       continue;
+               }
+               hook = hid_sticky_drivers[i]->hook;
+               if (hook && hook->pre_report_event) {
+                       ret = hook->pre_report_event(report, interrupt);
+                       if (!ret)
+                               break;
+               }
+       }
+       return ret;
+}
+
+static void hid_report_event(struct hid_device *hid,
+                                       struct hid_report *report, int 
interrupt)
+{
+       struct hid_hook *hook;
+       int i;
+
+       if (!hid->driver)
+               return;
+               
+       hook = hid->driver->hook;
+       if (hook && hook->report_event) {
+               hook->report_event(report, interrupt);
+               return;
+       }
+       
+       hidinput_report_event(hid, report);
+       
+       for (i=0; i<NR_STICKY; ++i) {
+               if (!hid_sticky_drivers[i] || !test_bit(i, &hid->sticky_driver))
+                       continue;
+               if (hid_sticky_driver_exit(i)) {
+                       clear_bit(i, &hid->sticky_driver);
+                       continue;
+               }
+               hook = hid_sticky_drivers[i]->hook;
+               if (hook && hook->report_event)
+                       hook->report_event(report, interrupt);
+       }
+}
+
 int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int 
interrupt)
 {
        struct hid_report_enum *report_enum = hid->report_enum + type;
        struct hid_report *report;
        int n, rsize;
-
-       if (!hid)
-               return -ENODEV;
+       
+       if (!hid || !hid->driver)
+               return -1;
 
        if (!size) {
                dbg("empty report");
@@ -976,34 +1078,14 @@ int hid_input_report(struct hid_device *
                dbg("report %d is too short, (%d < %d)", report->id, size, 
rsize);
                memset(data + size, 0, rsize - size);
        }
-
-       if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
-               hid->hiddev_report_event(hid, report);
-       if (hid->claimed & HID_CLAIMED_HIDRAW)
-               hidraw_report_event(hid, data, size);
-
+       hid_raw_event(hid, type, data, size, interrupt);
+       if (!hid_report_pre_event(hid, report, interrupt))
+               return 0;
        for (n = 0; n < report->maxfield; n++)
                hid_input_field(hid, report->field[n], data, interrupt);
-
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_report_event(hid, report);
+       hid_report_event(hid, report, interrupt);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
-static int __init hid_init(void)
-{
-       return hidraw_init();
-}
-
-static void __exit hid_exit(void)
-{
-       hidraw_exit();
-}
-
-module_init(hid_init);
-module_exit(hid_exit);
-
-MODULE_LICENSE(DRIVER_LICENSE);
-
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-input.c 
linux-2.6.21-rc6-mm1.new/drivers/hid/hid-input.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-input.c   2007-04-10 
09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/hid-input.c    2007-04-15 
21:35:15.000000000 +0800
@@ -33,11 +33,7 @@
 
 #include <linux/hid.h>
 #include <linux/hid-debug.h>
-
-static int hid_pb_fnmode = 1;
-module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
-               "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = 
fkeysfirst)");
+#include "hid-inter.h"
 
 #define unk    KEY_UNKNOWN
 
@@ -73,183 +69,13 @@ static const struct {
 #define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
 #define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
 
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-
-struct hidinput_key_translation {
-       u16 from;
-       u16 to;
-       u8 flags;
-};
-
-#define POWERBOOK_FLAG_FKEY 0x01
-
-static struct hidinput_key_translation powerbook_fn_keys[] = {
-       { KEY_BACKSPACE, KEY_DELETE },
-       { KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
-       { KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
-       { KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
-       { KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
-       { KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
-       { KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
-       { KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
-       { KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
-       { KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
-       { KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
-       { KEY_UP,       KEY_PAGEUP },
-       { KEY_DOWN,     KEY_PAGEDOWN },
-       { KEY_LEFT,     KEY_HOME },
-       { KEY_RIGHT,    KEY_END },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_numlock_keys[] = {
-       { KEY_J,        KEY_KP1 },
-       { KEY_K,        KEY_KP2 },
-       { KEY_L,        KEY_KP3 },
-       { KEY_U,        KEY_KP4 },
-       { KEY_I,        KEY_KP5 },
-       { KEY_O,        KEY_KP6 },
-       { KEY_7,        KEY_KP7 },
-       { KEY_8,        KEY_KP8 },
-       { KEY_9,        KEY_KP9 },
-       { KEY_M,        KEY_KP0 },
-       { KEY_DOT,      KEY_KPDOT },
-       { KEY_SLASH,    KEY_KPPLUS },
-       { KEY_SEMICOLON, KEY_KPMINUS },
-       { KEY_P,        KEY_KPASTERISK },
-       { KEY_MINUS,    KEY_KPEQUAL },
-       { KEY_0,        KEY_KPSLASH },
-       { KEY_F6,       KEY_NUMLOCK },
-       { KEY_KPENTER,  KEY_KPENTER },
-       { KEY_BACKSPACE, KEY_BACKSPACE },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_iso_keyboard[] = {
-       { KEY_GRAVE,    KEY_102ND },
-       { KEY_102ND,    KEY_GRAVE },
-       { }
-};
-
-static struct hidinput_key_translation *find_translation(struct 
hidinput_key_translation *table, u16 from)
-{
-       struct hidinput_key_translation *trans;
-
-       /* Look for the translation */
-       for (trans = table; trans->from; trans++)
-               if (trans->from == from)
-                       return trans;
-
-       return NULL;
-}
-
-static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
-               struct hid_usage *usage, __s32 value)
-{
-       struct hidinput_key_translation *trans;
-
-       if (usage->code == KEY_FN) {
-               if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
-               else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
-
-               input_event(input, usage->type, usage->code, value);
-
-               return 1;
-       }
-
-       if (hid_pb_fnmode) {
-               int do_translate;
-
-               trans = find_translation(powerbook_fn_keys, usage->code);
-               if (trans) {
-                       if (test_bit(usage->code, hid->pb_pressed_fn))
-                               do_translate = 1;
-                       else if (trans->flags & POWERBOOK_FLAG_FKEY)
-                               do_translate =
-                                       (hid_pb_fnmode == 2 &&  (hid->quirks & 
HID_QUIRK_POWERBOOK_FN_ON)) ||
-                                       (hid_pb_fnmode == 1 && !(hid->quirks & 
HID_QUIRK_POWERBOOK_FN_ON));
-                       else
-                               do_translate = (hid->quirks & 
HID_QUIRK_POWERBOOK_FN_ON);
-
-                       if (do_translate) {
-                               if (value)
-                                       set_bit(usage->code, 
hid->pb_pressed_fn);
-                               else
-                                       clear_bit(usage->code, 
hid->pb_pressed_fn);
-
-                               input_event(input, usage->type, trans->to, 
value);
-
-                               return 1;
-                       }
-               }
-
-               if (test_bit(usage->code, hid->pb_pressed_numlock) ||
-                               test_bit(LED_NUML, input->led)) {
-                       trans = find_translation(powerbook_numlock_keys, 
usage->code);
-
-                       if (trans) {
-                               if (value)
-                                       set_bit(usage->code, 
hid->pb_pressed_numlock);
-                               else
-                                       clear_bit(usage->code, 
hid->pb_pressed_numlock);
-
-                               input_event(input, usage->type, trans->to, 
value);
-                       }
-
-                       return 1;
-               }
-       }
-
-       if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
-               trans = find_translation(powerbook_iso_keyboard, usage->code);
-               if (trans) {
-                       input_event(input, usage->type, trans->to, value);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static void hidinput_pb_setup(struct input_dev *input)
-{
-       struct hidinput_key_translation *trans;
-
-       set_bit(KEY_NUMLOCK, input->keybit);
-
-       /* Enable all needed keys */
-       for (trans = powerbook_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_numlock_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_iso_keyboard; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-}
-#else
-static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev 
*input,
-               struct hid_usage *usage, __s32 value)
-{
-       return 0;
-}
-
-static inline void hidinput_pb_setup(struct input_dev *input)
-{
-}
-#endif
-
-static void hidinput_configure_usage(struct hid_input *hidinput, struct 
hid_field *field,
+static void hidinput_configure_usage(struct input_dev *input, struct hid_field 
*field,
                                     struct hid_usage *usage)
 {
-       struct input_dev *input = hidinput->input;
        struct hid_device *device = input->private;
        int max = 0, code;
        unsigned long *bit = NULL;
 
-       field->hidinput = hidinput;
-
 #ifdef CONFIG_HID_DEBUG
        printk(KERN_DEBUG "Mapping: ");
        hid_resolv_usage(usage->hid);
@@ -606,17 +432,7 @@ static void hidinput_configure_usage(str
                        goto ignore;
 
                case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB 
keyboards */
-
                        set_bit(EV_REP, input->evbit);
-                       switch(usage->hid & HID_USAGE) {
-                               case 0x003:
-                                       /* The fn key on Apple PowerBooks */
-                                       map_key_clear(KEY_FN);
-                                       hidinput_pb_setup(input);
-                                       break;
-
-                               default:    goto ignore;
-                       }
                        break;
 
                case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media 
Remote */
@@ -746,8 +562,87 @@ ignore:
        return;
 }
 
+static void inline hid_driver_hook_usage(struct input_dev *input,
+                                               struct hid_usage *usage,
+                                               struct usage_block *usage_block)
+{
+       unsigned long *bits;
+       struct hid_device *hid;
+
+       hid = input->private;
+       switch (usage_block->event) {
+       case EV_KEY:
+               bits = input->keybit;
+               break;
+       case EV_REL:
+               bits = input->relbit;
+               break;
+       case EV_ABS:
+               bits = input->relbit;
+               break;
+       case EV_MSC:
+               bits = input->absbit;
+               break;
+       case EV_SW:
+               bits = input->swbit;
+               break;
+       case EV_LED:
+               bits = input->ledbit;
+               break;
+       case EV_SND:
+               bits = input->sndbit;
+               break;
+       case EV_FF:
+               bits = input->ffbit;
+               break;
+       case EV_FF_STATUS:
+               bits = NULL;
+               break;
+       default:
+               return;
+       }
+
+       usage->code = usage_block->code;
+       usage->type = usage_block->event;
+       set_bit(usage_block->event, input->evbit);
+       if (bits)
+               set_bit(usage_block->code, bits);
+}
+
+static void hid_driver_hook_field(struct hid_driver *driver,
+                                               struct hid_field *field,
+                                               struct hid_usage *hid_usage)
+{
+       struct hid_hook *hook = driver->hook;
+       struct input_dev *input = field->hidinput->input;
+       struct usage_block *usage_block;
+       struct usage_page_block *page_block;
+       int page;
+       int usage;
+
+       if (!hook)
+               return;
+               
+       page = (hid_usage->hid & HID_USAGE_PAGE);
+       usage = (hid_usage->hid & HID_USAGE);
+       page_block = hook->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;
+                       hid_driver_hook_usage(input, hid_usage, usage_block);
+               }
+       }
+       if (hook->setup_usage)
+               hook->setup_usage(field, hid_usage);
+}
+
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, 
struct hid_usage *usage, __s32 value)
 {
+       struct hid_input *hidinput;
        struct input_dev *input;
        int *quirks = &hid->quirks;
 
@@ -759,6 +654,8 @@ void hidinput_hid_event(struct hid_devic
        if (!usage->type)
                return;
 
+       hidinput = field->hidinput;
+
        if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 
0x00090005))
                || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && 
(usage->hid == 0x00090007))) {
                if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
@@ -776,9 +673,6 @@ void hidinput_hid_event(struct hid_devic
                return;
        }
 
-       if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && 
hidinput_pb_event(hid, input, usage, value))
-               return;
-
        if (usage->hat_min < usage->hat_max || usage->hat_dir) {
                int hat_dir = usage->hat_dir;
                if (!hat_dir)
@@ -828,10 +722,14 @@ void hidinput_hid_event(struct hid_devic
        if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
                input_event(input, usage->type, usage->code, 0);
 }
+EXPORT_SYMBOL(hidinput_hid_event);
 
 void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
 {
        struct hid_input *hidinput;
+       
+       if (!hid->driver)
+               return;
 
        list_for_each_entry(hidinput, &hid->inputs, list)
                input_sync(hidinput->input);
@@ -855,16 +753,81 @@ int hidinput_find_field(struct hid_devic
 }
 EXPORT_SYMBOL_GPL(hidinput_find_field);
 
+static int hidinput_input_event(struct input_dev *dev, unsigned int type,
+                                               unsigned int code, int value)
+{
+       struct hid_device *hid = dev->private;
+       struct hid_transport *tl;
+       int ret;
+
+       if (!hid || !hid->driver)
+               return 0;
+       if (hid->driver->event)
+               return hid->driver->event(dev, type, code, value);
+       ret = 0;
+       tl = hid_transports[hid->bus];
+       if (tl->event)
+               ret = tl->event(dev, type, code, value);
+       return ret;
+}
+
+int hid_open(struct hid_device *hid)
+{
+       struct hid_transport *tl;
+       int ret;
+       
+       if (hid->driver->open)
+               return hid->driver->open(hid);
+       ret = 0;
+       tl = hid_transports[hid->bus];
+       if (tl->open)
+               ret = tl->open(hid);
+       return ret;
+}
+EXPORT_SYMBOL(hid_open);
+
 static int hidinput_open(struct input_dev *dev)
 {
        struct hid_device *hid = dev->private;
-       return hid->hid_open(hid);
+       
+       if (!hid || !hid->driver)
+               return 0;
+       return hid_open(hid);
 }
 
+void hid_close(struct hid_device *hid)
+{
+       struct hid_transport *tl;
+       
+       if (hid->driver->close) {
+               hid->driver->close(hid);
+               return;
+       }
+       tl = hid_transports[hid->bus];
+       if (tl->close)
+               tl->close(hid);
+}
+EXPORT_SYMBOL(hid_close);
+
 static void hidinput_close(struct input_dev *dev)
 {
        struct hid_device *hid = dev->private;
-       hid->hid_close(hid);
+       
+       if (!hid || !hid->driver)
+               return;
+       hid_close(hid);
+       return;
+}
+
+static inline void hidinput_register_inputdev(struct hid_driver *driver,
+                                               struct input_dev *input)
+{
+       struct hid_hook *hook = driver->hook;
+       
+       if (hook && hook->register_inputdev)
+               hook->register_inputdev(input);
+       else
+               input_register_device(input);
 }
 
 /*
@@ -875,13 +838,18 @@ static void hidinput_close(struct input_
 
 int hidinput_connect(struct hid_device *hid)
 {
+       struct hid_driver *drv;
        struct hid_report *report;
        struct hid_input *hidinput = NULL;
        struct input_dev *input_dev;
        int i, j, k;
        int max_report_type = HID_OUTPUT_REPORT;
 
-       INIT_LIST_HEAD(&hid->inputs);
+       printk("connect %p\n", hid);
+
+       drv = hid->driver;
+       if (!drv)
+               return -1;
 
        for (i = 0; i < hid->maxcollection; i++)
                if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
@@ -912,7 +880,7 @@ int hidinput_connect(struct hid_device *
                                }
 
                                input_dev->private = hid;
-                               input_dev->event = hid->hidinput_input_event;
+                               input_dev->event = hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
 
@@ -928,10 +896,15 @@ int hidinput_connect(struct hid_device *
                                list_add_tail(&hidinput->list, &hid->inputs);
                        }
 
-                       for (i = 0; i < report->maxfield; i++)
+                       for (i = 0; i < report->maxfield; i++) {
+                               report->field[i]->hidinput = hidinput;
                                for (j = 0; j < report->field[i]->maxusage; j++)
-                                       hidinput_configure_usage(hidinput, 
report->field[i],
+                                       
hidinput_configure_usage(hidinput->input, report->field[i],
                                                                 
report->field[i]->usage + j);
+                                       hid_driver_hook_field(drv,
+                                                               
report->field[i],
+                                                       report->field[i]->usage 
+ j);
+                       }
 
                        if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
                                /* This will leave hidinput NULL, so that it
@@ -940,13 +913,13 @@ int hidinput_connect(struct hid_device *
                                 * UGCI) cram a lot of unrelated inputs into the
                                 * same interface. */
                                hidinput->report = report;
-                               input_register_device(hidinput->input);
+                               hidinput_register_inputdev(drv, 
hidinput->input);
                                hidinput = NULL;
                        }
                }
 
        if (hidinput)
-               input_register_device(hidinput->input);
+               hidinput_register_inputdev(drv, hidinput->input);
 
        return 0;
 }
@@ -956,6 +929,10 @@ void hidinput_disconnect(struct hid_devi
 {
        struct hid_input *hidinput, *next;
 
+       BUG_ON(!hid->driver);
+
+       printk("disconnect %p\n", hid);
+
        list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
                list_del(&hidinput->list);
                input_unregister_device(hidinput->input);
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-inter.h 
linux-2.6.21-rc6-mm1.new/drivers/hid/hid-inter.h
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/hid-inter.h   1970-01-01 
08:00:00.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/hid-inter.h    2007-04-11 
09:24:54.000000000 +0800
@@ -0,0 +1,26 @@
+/*
+ *  HID abstract layer for Linux driver model
+ *
+ *  Copyright (c) 2007 Li Yu
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef HID_INTERNAL_H__
+#define HID_INTERNAL_H__
+
+#include <linux/input.h> /* for BUS_MAX */
+
+#define NR_STICKY 32
+
+extern struct hid_transport* hid_transports[BUS_MAX];
+extern struct hid_driver* hid_sticky_drivers[NR_STICKY];
+extern int hid_sticky_driver_exit(int i);
+
+#endif
+
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/hidraw.c 
linux-2.6.21-rc6-mm1.new/drivers/hid/hidraw.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/hidraw.c      2007-04-10 
09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/hidraw.c       2007-04-15 
21:30:58.000000000 +0800
@@ -32,6 +32,7 @@
 #include <linux/mutex.h>
 
 #include <linux/hidraw.h>
+#include "hid-inter.h"
 
 static int hidraw_major;
 static struct cdev hidraw_cdev;
@@ -105,12 +106,17 @@ static ssize_t hidraw_write(struct file 
 {
        unsigned int minor = iminor(file->f_path.dentry->d_inode);
        struct hid_device *dev = hidraw_table[minor]->hid;
+       struct hid_driver *drv = dev->driver;
+       struct hid_hook *hook = drv->hook;
        __u8 *buf;
        int ret = 0;
 
-       if (!dev->hid_output_raw_report)
+       if (hid_transports[dev->bus]->raw_report)
+               goto really_start;
+       if (!hook || !hook->raw_report)
                return -ENODEV;
 
+really_start:
        if (count > HID_MIN_BUFFER_SIZE) {
                printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
                                current->pid);
@@ -132,7 +138,11 @@ static ssize_t hidraw_write(struct file 
                goto out;
        }
 
-       ret = dev->hid_output_raw_report(dev, buf, count);
+       if (hook && hook->raw_report)
+               ret = hook->raw_report(dev, buf, count);
+       else
+               ret = hid_transports[dev->bus]->raw_report(dev, buf, count);
+       
 out:
        kfree(buf);
        return ret;
@@ -178,7 +188,7 @@ static int hidraw_open(struct inode *ino
 
        dev = hidraw_table[minor];
        if (!dev->open++)
-               dev->hid->hid_open(dev->hid);
+               err = hid_open(dev->hid);
 
 out_unlock:
        spin_unlock(&minors_lock);
@@ -203,7 +213,7 @@ static int hidraw_release(struct inode *
        dev = hidraw_table[minor];
        if (!dev->open--) {
                if (list->hidraw->exist)
-                       dev->hid->hid_close(dev->hid);
+                       dev->hid->driver->close(dev->hid);
                else
                        kfree(list->hidraw);
        }
@@ -264,11 +274,15 @@ static const struct file_operations hidr
        .ioctl =        hidraw_ioctl,
 };
 
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+static int hidraw_raw_event(struct hid_device *hid, int type, u8 *data,
+                                                       int len, int interrupt)
 {
        struct hidraw *dev = hid->hidraw;
        struct hidraw_list *list;
 
+       if (!dev)
+               return -1;
+
        list_for_each_entry(list, &dev->list, node) {
                list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
                list->buffer[list->head].len = len;
@@ -277,10 +291,10 @@ void hidraw_report_event(struct hid_devi
        }
 
        wake_up_interruptible(&dev->wait);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(hidraw_report_event);
 
-int hidraw_connect(struct hid_device *hid)
+static int hidraw_connect(struct hid_device *hid)
 {
        int minor, result = -EINVAL;
        struct hidraw *dev;
@@ -332,12 +346,14 @@ out:
        return result;
 
 }
-EXPORT_SYMBOL_GPL(hidraw_connect);
 
-void hidraw_disconnect(struct hid_device *hid)
+static void hidraw_disconnect(struct hid_device *hid)
 {
        struct hidraw *hidraw = hid->hidraw;
 
+       if (!hidraw)
+               return;
+
        hidraw->exist = 0;
 
        spin_lock(&minors_lock);
@@ -347,19 +363,36 @@ void hidraw_disconnect(struct hid_device
        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
        if (hidraw->open) {
-               hid->hid_close(hid);
+               hid_close(hid);
                wake_up_interruptible(&hidraw->wait);
        } else {
                kfree(hidraw);
        }
 }
-EXPORT_SYMBOL_GPL(hidraw_disconnect);
+
+static struct hid_hook hidraw_hook = {
+       .raw_event = hidraw_raw_event,
+};
+
+static struct hid_driver hid_hidraw_driver = {
+       .name = "hidraw",
+       .version = "0.1.0",
+       .module = THIS_MODULE,
+       .probe = hidraw_connect,
+       .remove = hidraw_disconnect,
+       .hook = &hidraw_hook,
+};
 
 int __init hidraw_init(void)
 {
        int result;
        dev_t dev_id;
 
+       set_hid_driver_sticky(&hid_hidraw_driver);
+       result = hid_register_driver(&hid_hidraw_driver);
+       if (result)
+               goto out;
+
        result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
                        HIDRAW_MAX_DEVICES, "hidraw");
 
@@ -388,8 +421,13 @@ void __exit hidraw_exit(void)
 {
        dev_t dev_id = MKDEV(hidraw_major, 0);
 
+       hid_unregister_driver(&hid_hidraw_driver);
        cdev_del(&hidraw_cdev);
        class_destroy(hidraw_class);
        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 
 }
+
+module_init(hidraw_init);
+module_exit(hidraw_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/Kconfig 
linux-2.6.21-rc6-mm1.new/drivers/hid/Kconfig
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/Kconfig       2007-04-10 
09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/Kconfig        2007-04-16 
13:44:21.000000000 +0800
@@ -37,7 +37,7 @@ config HID_DEBUG
        If unsure, say N
 
 config HIDRAW
-       bool "/dev/hidraw raw HID device support"
+       tristate "/dev/hidraw raw HID device support"
        depends on HID
        ---help---
        Say Y here if you want to support HID devices (from the USB
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/Makefile 
linux-2.6.21-rc6-mm1.new/drivers/hid/Makefile
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/Makefile      2007-04-10 
09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/Makefile       2007-04-17 
09:23:27.000000000 +0800
@@ -1,7 +1,7 @@
 #
 # Makefile for the HID driver
 #
-hid-objs                       := hid-core.o hid-input.o
+hid-objs                       := hid-core.o hid-input.o hid-al.o
 
 obj-$(CONFIG_HID)              += hid.o
 
@@ -9,6 +9,13 @@ hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
 hid-$(CONFIG_HIDRAW)           += hidraw.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
+obj-$(CONFIG_HID_PID)          += usbhid/
+obj-$(CONFIG_THRUSTMASTER_FF)   += usbhid/
+obj-$(CONFIG_ZEROPLUS_FF)       += usbhid/
+obj-$(CONFIG_POWERBOOK)                += usbhid/
+obj-$(CONFIG_LOGITECH_FF)       += usbhid/
+obj-$(CONFIG_PANTHERLORD_FF)    += usbhid/
+obj-$(CONFIG_USB_HIDDEV)       += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
 obj-$(CONFIG_USB_KBD)          += usbhid/
 




-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
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