[PATCH] hid: hid bus prototype 20070416 in splited patches.
Li Yu <[email protected]>
| Newsgroups | gmane.linux.usb.devel,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
Hi, There are the HID bus prototype 20070416 in splited patch form in the attachment. I am sorry there are in the attachment, if not so, their indentation will be mangling by thunderbird. These patches should be can apply on 2.6.21-rc6-mm1. Good luck. - Li Yu ------------------------------------------------------------------------- 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/ _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
hidbus.core.patch
(text/x-patch, 37.8 KB)
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/
hidbus.headers.patch
(text/x-patch, 10.5 KB)
diff -Naurp linux-2.6.21-rc6-mm1.orig/include/linux/hiddev.h linux-2.6.21-rc6-mm1.new/include/linux/hiddev.h
--- linux-2.6.21-rc6-mm1.orig/include/linux/hiddev.h 2007-02-05 02:44:54.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/include/linux/hiddev.h 2007-04-11 09:05:29.000000000 +0800
@@ -218,23 +218,5 @@ struct hid_usage;
struct hid_field;
struct hid_report;
-#ifdef CONFIG_USB_HIDDEV
-int hiddev_connect(struct hid_device *);
-void hiddev_disconnect(struct hid_device *);
-void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value);
-void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
-int __init hiddev_init(void);
-void hiddev_exit(void);
-#else
-static inline int hiddev_connect(struct hid_device *hid) { return -1; }
-static inline void hiddev_disconnect(struct hid_device *hid) { }
-static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value) { }
-static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
-static inline int hiddev_init(void) { return 0; }
-static inline void hiddev_exit(void) { }
-#endif
-
#endif
#endif
diff -Naurp linux-2.6.21-rc6-mm1.orig/include/linux/hid.h linux-2.6.21-rc6-mm1.new/include/linux/hid.h
--- linux-2.6.21-rc6-mm1.orig/include/linux/hid.h 2007-04-10 09:16:50.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/include/linux/hid.h 2007-04-16 13:09:51.000000000 +0800
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/input.h>
+#include <asm/bitops.h>
/*
* USB HID (Human Interface Device) interface class code
@@ -270,6 +271,7 @@ struct hid_item {
#define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000
#define HID_QUIRK_RESET_LEDS 0x00400000
+#define HID_QUIRK_SKIP 0x80000000
/*
* This is the global environment of the parser. This information is
@@ -403,55 +405,112 @@ struct hid_input {
struct input_dev *input;
};
-struct hid_device { /* device report descriptor */
+struct hid_driver;
+struct hid_device { /* device report descriptor */
+ struct device device;
+ struct module *module;
+ struct hid_driver *driver;
+ unsigned long sticky_driver;
+ unsigned long flags;
+ void *tl_data; /* Transports layer data. */
+ void *hidraw; /* It will be remove soon. */
+ int quirks;
+
__u8 *rdesc;
unsigned rsize;
- struct hid_collection *collection; /* List of HID collections */
- unsigned collection_size; /* Number of allocated hid_collections */
- unsigned maxcollection; /* Number of parsed collections */
- unsigned maxapplication; /* Number of applications */
- unsigned short bus; /* BUS ID */
- unsigned short vendor; /* Vendor ID */
- unsigned short product; /* Product ID */
- unsigned version; /* HID version */
- unsigned country; /* HID country */
+ struct hid_collection *collection; /* List of HID collections */
+ unsigned collection_size; /* Number of allocated hid_collections */
+ unsigned maxcollection; /* Number of parsed collections */
+ unsigned maxapplication; /* Number of applications */
+ unsigned short bus; /* BUS ID */
+ unsigned short vendor; /* Vendor ID */
+ unsigned short product; /* Product ID */
+ unsigned version; /* HID version */
+ unsigned country; /* HID country */
+ int open; /* Is the device open by anyone? */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
+ void *private; /* Data for specific driver */
- struct device *dev; /* device */
-
- unsigned claimed; /* Claimed by hidinput, hiddev? */
- unsigned quirks; /* Various quirks the device can pull on us */
+ void (*shutdown)(struct hid_device *dev);
- struct list_head inputs; /* The list of inputs */
- void *hiddev; /* The hiddev structure */
- void *hidraw;
- int minor; /* Hiddev minor number */
-
- wait_queue_head_t wait; /* For sleeping */
-
- int open; /* is the device open by anyone? */
- char name[128]; /* Device name */
- char phys[64]; /* Device physical location */
- char uniq[64]; /* Device unique identifier (serial #) */
-
- void *driver_data;
-
- /* device-specific function pointers */
- int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
- int (*hid_open) (struct hid_device *);
- void (*hid_close) (struct hid_device *);
-
- /* hiddev event handler */
- void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
- struct hid_usage *, __s32);
- void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
-
- /* handler for raw output data, used by hidraw */
- int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
- unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
- unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
-#endif
+ struct device *dev; /* Physical device(USB, Bluetooth, etc.) */
+ char name[128]; /* Device name */
+ char phys[64]; /* Device physical location */
+ char uniq[64]; /* Device unique identifier (serial #) */
+ struct list_head inputs; /* The list of inputs */
+};
+#define to_hid_device(dev) container_of(dev, struct hid_device, device);
+
+#define HID_IGNORE_VENDOR 1
+#define HID_IGNORE_PRODUCT 2
+#define HID_IGNORE_VERSION 4
+#define HID_IGNORE_COUNTRY 8
+
+struct skip_id {
+ struct list_head node;
+ unsigned int vendor;
+ unsigned int product;
+ unsigned int version;
+ unsigned int country;
+ unsigned int mask;
+};
+
+struct hid_hook;
+struct hid_driver {
+ char name[64];
+ char version[64];
+ struct module *module;
+ struct device_driver driver;
+ unsigned long flags;
+
+ unsigned short bus;
+ struct hid_hook *hook;
+ struct list_head skip_table;
+
+ void *private;
+
+ int (*match)(struct hid_driver *, struct hid_device *);
+ int (*probe)(struct hid_device *);
+ void (*remove)(struct hid_device *);
+ void (*shutdown)(struct hid_device *);
+ int (*event)(struct input_dev *, unsigned int, unsigned int, int);
+ int (*open)(struct hid_device *);
+ void (*close)(struct hid_device *);
+};
+#define to_hid_driver(drv) container_of(drv, struct hid_driver, driver);
+
+struct hid_transport {
+ struct module *module;
+ unsigned short bus;
+ void (*update_busid)(struct hid_device *);
+ int (*event)(struct input_dev *, unsigned int, unsigned int, int);
+ int (*open)(struct hid_device *);
+ void (*close)(struct hid_device *);
+ int (*raw_report)(struct hid_device *, u8 *, size_t);
+ void *private;
+};
+
+struct usage_page_block;
+struct hid_hook {
+ void (*setup_usage)(struct hid_field*, struct hid_usage*);
+ void (*register_inputdev)(struct input_dev*);
+ int (*hid_event)(struct hid_field*, struct hid_usage*, __s32, int);
+ int (*pre_report_event)(struct hid_report*, int);
+ int (*report_event)(struct hid_report*, int);
+ int (*raw_event)(struct hid_device *, int, u8 *, int, int);
+ int (*raw_report)(struct hid_device *, u8 *, size_t);
+ struct usage_page_block *usage_page_table;
+};
+
+struct usage_block {
+ int usage; /* usage code */
+ int event; /* input event type, e.g. EV_KEY. */
+ int code; /* input subsystem code, e.g. KEY_F1. */
+};
+
+struct usage_page_block {
+ int page; /* usage page code */
+ struct usage_block *usage_blockes;
};
#define HID_GLOBAL_STACK_SIZE 4
@@ -500,22 +559,38 @@ void hid_output_report(struct hid_report
void hid_free_device(struct hid_device *device);
struct hid_device *hid_parse_report(__u8 *start, unsigned size);
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
-
-int hid_lgff_init(struct hid_device *hid);
-int hid_plff_init(struct hid_device *hid);
-int hid_tmff_init(struct hid_device *hid);
-int hid_zpff_init(struct hid_device *hid);
-#ifdef CONFIG_HID_PID
-int hid_pidff_init(struct hid_device *hid);
-#else
-static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
-#endif
+#define hid_flag_accessor(DD, name, FLAG) \
+static inline void set_##DD##_##name(struct DD* dd)\
+{\
+ set_bit(FLAG, &dd->flags);\
+}\
+static inline void clear_##DD##_##name(struct DD* dd)\
+{\
+ clear_bit(FLAG, &dd->flags);\
+}\
+static inline int is_##DD##_##name(struct DD* dd)\
+{\
+ return test_bit(FLAG, &dd->flags);\
+}
+
+/* set_hid_driver_sticky()/is_hid_driver_sticky() */
+#define HID_DRV_STICKY (0x1UL)
+hid_flag_accessor(hid_driver, sticky, HID_DRV_STICKY)
+
+static inline struct hid_device *hid_new_device(int gfp)
+{
+ return kzalloc(sizeof(struct hid_device), gfp);
+}
+
+extern int hid_register_transport(struct hid_transport *);
+extern void hid_unregister_transport(struct hid_transport *);
+extern int hid_register_device(struct hid_device *);
+extern void hid_unregister_device(struct hid_device *);
+extern int hid_register_driver(struct hid_driver *);
+extern void hid_unregister_driver(struct hid_driver *);
+extern int hid_open(struct hid_device *);
+extern void hid_close(struct hid_device *);
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
-#endif
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
__FILE__ , ## arg)
diff -Naurp linux-2.6.21-rc6-mm1.orig/include/linux/hidraw.h linux-2.6.21-rc6-mm1.new/include/linux/hidraw.h
--- linux-2.6.21-rc6-mm1.orig/include/linux/hidraw.h 2007-04-10 09:16:50.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/include/linux/hidraw.h 2007-04-11 09:05:31.000000000 +0800
@@ -67,20 +67,6 @@ struct hidraw_list {
struct mutex read_mutex;
};
-#ifdef CONFIG_HIDRAW
-int hidraw_init(void);
-void hidraw_exit(void);
-void hidraw_report_event(struct hid_device *, u8 *, int);
-int hidraw_connect(struct hid_device *);
-void hidraw_disconnect(struct hid_device *);
-#else
-static inline int hidraw_init(void) { return 0; }
-static inline void hidraw_exit(void) { }
-static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
-static inline int hidraw_connect(struct hid_device *hid) { return -1; }
-static inline void hidraw_disconnect(struct hid_device *hid) { }
-#endif
-
#endif
#endif
diff -Naurp linux-2.6.21-rc6-mm1.orig/include/linux/input.h linux-2.6.21-rc6-mm1.new/include/linux/input.h
--- linux-2.6.21-rc6-mm1.orig/include/linux/input.h 2007-04-10 09:16:50.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/include/linux/input.h 2007-04-10 10:24:51.000000000 +0800
@@ -679,7 +679,7 @@ struct input_absinfo {
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
-
+#define BUS_MAX (BUS_GSC+1)
/*
* Values describing the status of a force-feedback effect
*/
hidbus.usb.core.patch
(text/x-patch, 19.6 KB)
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-core.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-core.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-core.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-core.c 2007-04-15 21:29:31.000000000 +0800
@@ -29,10 +29,6 @@
#include <linux/usb.h>
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include <linux/hid-debug.h>
-#include <linux/hidraw.h>
#include "usbhid.h"
/*
@@ -299,6 +295,39 @@ static const struct hid_blacklist {
__u32 quirks;
} hid_blacklist[] = {
+ /* the hid-zpff.c will these two devices */
+ { 0x46d, 0x0005, HID_QUIRK_SKIP },
+ { 0xc12, 0x0030, HID_QUIRK_SKIP },
+
+ /* the hid-tmff.c will handle this */
+ { 0x044f, 0xb304, HID_QUIRK_SKIP },
+
+ /* the hid-plff.c will handle this */
+ { 0x0810, 0x0001, HID_QUIRK_SKIP },
+
+ /* the hid-lgff.c will handle follow these five devices */
+ { USB_VENDOR_ID_LOGITECH, 0xc221, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_LOGITECH, 0xc219, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_LOGITECH, 0xc283, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_LOGITECH, 0xc294, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_LOGITECH, 0xc295, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_LOGITECH, 0xca03, HID_QUIRK_SKIP },
+
+ /* the hid-pb.c will handle these thirteen devices */
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_SKIP },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_SKIP },
+
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
@@ -306,7 +335,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
-
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
@@ -462,25 +490,28 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
{ 0, 0 }
};
+static void usbhid_update_busid(struct hid_device *dev)
+{
+ static atomic_t usb_hiddev_idx = ATOMIC_INIT(-1);
+
+ snprintf(dev->device.bus_id, BUS_ID_SIZE, "U:%04x:%04x:%d",
+ le16_to_cpu(dev->vendor),
+ le16_to_cpu(dev->product),
+ atomic_add_return(1, &usb_hiddev_idx));
+}
+
+static inline void usbhid_wake_up(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = (struct usbhid_device*)hid->tl_data;
+
+ wake_up(&usbhid->wait);
+}
+
/*
* Input submission and I/O error handler.
*/
@@ -492,7 +523,7 @@ static int hid_start_in(struct hid_devic
{
unsigned long flags;
int rc = 0;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
spin_lock_irqsave(&usbhid->inlock, flags);
if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
@@ -509,7 +540,9 @@ static int hid_start_in(struct hid_devic
static void hid_retry_timeout(unsigned long _hid)
{
struct hid_device *hid = (struct hid_device *) _hid;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
+
+ BUG_ON(!usbhid);
dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
if (hid_start_in(hid))
@@ -564,7 +597,9 @@ static void hid_reset(struct work_struct
static void hid_io_error(struct hid_device *hid)
{
unsigned long flags;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
+
+ BUG_ON(!usbhid);
spin_lock_irqsave(&usbhid->inlock, flags);
@@ -606,7 +641,7 @@ done:
static void hid_irq_in(struct urb *urb)
{
struct hid_device *hid = urb->context;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
int status;
switch (urb->status) {
@@ -653,7 +688,7 @@ static void hid_irq_in(struct urb *urb)
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
report = usbhid->out[usbhid->outtail];
@@ -676,7 +711,7 @@ static int hid_submit_ctrl(struct hid_de
struct hid_report *report;
unsigned char dir;
int len;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
dir = usbhid->ctrl[usbhid->ctrltail].dir;
@@ -727,10 +762,12 @@ static int hid_submit_ctrl(struct hid_de
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
unsigned long flags;
int unplug = 0;
+ BUG_ON(!usbhid);
+
switch (urb->status) {
case 0: /* success */
break;
@@ -755,7 +792,7 @@ static void hid_irq_out(struct urb *urb)
if (usbhid->outhead != usbhid->outtail) {
if (hid_submit_out(hid)) {
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
- wake_up(&hid->wait);
+ usbhid_wake_up(hid);
}
spin_unlock_irqrestore(&usbhid->outlock, flags);
return;
@@ -763,7 +800,7 @@ static void hid_irq_out(struct urb *urb)
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
spin_unlock_irqrestore(&usbhid->outlock, flags);
- wake_up(&hid->wait);
+ usbhid_wake_up(hid);
}
#define USB_VENDOR_ID_BELKIN 0x050d
@@ -776,10 +813,11 @@ static void hid_irq_out(struct urb *urb)
static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
unsigned long flags;
int unplug = 0;
+
spin_lock_irqsave(&usbhid->ctrllock, flags);
switch (urb->status) {
@@ -808,7 +846,7 @@ static void hid_ctrl(struct urb *urb)
if (usbhid->ctrlhead != usbhid->ctrltail) {
if (hid_submit_ctrl(hid)) {
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
- wake_up(&hid->wait);
+ usbhid_wake_up(hid);
}
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
return;
@@ -816,14 +854,16 @@ static void hid_ctrl(struct urb *urb)
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- wake_up(&hid->wait);
+ usbhid_wake_up(hid);
}
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
int head;
unsigned long flags;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
+
+ BUG_ON(!usbhid);
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
@@ -867,6 +907,7 @@ void usbhid_submit_report(struct hid_dev
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
}
+EXPORT_SYMBOL_GPL(usbhid_submit_report);
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -893,9 +934,9 @@ static int usb_hidinput_input_event(stru
int usbhid_wait_io(struct hid_device *hid)
{
- struct usbhid_device *usbhid = hid->driver_data;
-
- if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+ struct usbhid_device *usbhid = hid->tl_data;
+
+ if (!wait_event_timeout(usbhid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
10*HZ)) {
dbg("timeout waiting for ctrl or out queue to clear");
@@ -904,6 +945,7 @@ int usbhid_wait_io(struct hid_device *hi
return 0;
}
+EXPORT_SYMBOL_GPL(usbhid_wait_io);
static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
{
@@ -935,23 +977,24 @@ int usbhid_open(struct hid_device *hid)
hid_io_error(hid);
return 0;
}
+EXPORT_SYMBOL_GPL(usbhid_open);
void usbhid_close(struct hid_device *hid)
{
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
if (!--hid->open)
usb_kill_urb(usbhid->urbin);
}
+EXPORT_SYMBOL_GPL(usbhid_close);
/*
* Initialize all reports
*/
-
void usbhid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
int err, ret;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
@@ -974,6 +1017,7 @@ void usbhid_init_reports(struct hid_devi
if (err)
warn("timeout initializing reports");
}
+EXPORT_SYMBOL_GPL(usbhid_init_reports);
/*
* Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
@@ -1032,7 +1076,7 @@ static void hid_find_max_report(struct h
static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
return -1;
@@ -1046,9 +1090,9 @@ static int hid_alloc_buffers(struct usb_
return 0;
}
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+static int usbhid_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
{
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1070,7 +1114,7 @@ static int usbhid_output_raw_report(stru
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
if (usbhid->inbuf)
usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
@@ -1179,7 +1223,6 @@ static struct hid_device *usb_hid_config
(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
return NULL;
-
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1234,8 +1277,9 @@ static struct hid_device *usb_hid_config
if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
goto fail;
- hid->driver_data = usbhid;
+ hid->tl_data = usbhid;
usbhid->hid = hid;
+ init_waitqueue_head(&usbhid->wait);
usbhid->bufsize = HID_MIN_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
@@ -1299,8 +1343,6 @@ static struct hid_device *usb_hid_config
goto fail;
}
- init_waitqueue_head(&hid->wait);
-
INIT_WORK(&usbhid->reset_work, hid_reset);
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
@@ -1353,14 +1395,6 @@ static struct hid_device *usb_hid_config
usbhid->urbctrl->setup_dma = usbhid->cr_dma;
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
- hid->hidinput_input_event = usb_hidinput_input_event;
- hid->hid_open = usbhid_open;
- hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
- hid->hiddev_hid_event = hiddev_hid_event;
- hid->hiddev_report_event = hiddev_report_event;
-#endif
- hid->hid_output_raw_report = usbhid_output_raw_report;
return hid;
fail:
@@ -1373,18 +1407,17 @@ fail:
return NULL;
}
-static void hid_disconnect(struct usb_interface *intf)
+static void hid_clean(struct hid_device *hid)
{
- struct hid_device *hid = usb_get_intfdata (intf);
struct usbhid_device *usbhid;
if (!hid)
return;
- usbhid = hid->driver_data;
+ usbhid = hid->tl_data;
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
- usb_set_intfdata(intf, NULL);
+ usb_set_intfdata(usbhid->intf, NULL);
spin_unlock_irq(&usbhid->inlock);
usb_kill_urb(usbhid->urbin);
usb_kill_urb(usbhid->urbout);
@@ -1393,13 +1426,6 @@ static void hid_disconnect(struct usb_in
del_timer_sync(&usbhid->io_retry);
flush_scheduled_work();
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_disconnect(hid);
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- hiddev_disconnect(hid);
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- hidraw_disconnect(hid);
-
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbctrl);
usb_free_urb(usbhid->urbout);
@@ -1408,6 +1434,16 @@ static void hid_disconnect(struct usb_in
hid_free_device(hid);
}
+static void hid_disconnect(struct usb_interface *intf)
+{
+ struct hid_device *hid = usb_get_intfdata (intf);
+
+ if (!hid)
+ return;
+ hid_unregister_device(hid);
+ hid_clean(hid);
+}
+
static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct hid_device *hid;
@@ -1426,43 +1462,12 @@ static int hid_probe(struct usb_interfac
if (hid->quirks & HID_QUIRK_RESET_LEDS)
usbhid_set_leds(hid);
- if (!hidinput_connect(hid))
- hid->claimed |= HID_CLAIMED_INPUT;
- if (!hiddev_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDDEV;
- if (!hidraw_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDRAW;
-
usb_set_intfdata(intf, hid);
- if (!hid->claimed) {
- printk ("HID device claimed by neither input, hiddev nor hidraw\n");
- hid_disconnect(intf);
- return -ENODEV;
- }
-
- if ((hid->claimed & HID_CLAIMED_INPUT))
- hid_ff_init(hid);
-
if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
intf->cur_altsetting->desc.bInterfaceNumber);
- printk(KERN_INFO);
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- printk("input");
- if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
- hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- printk("hiddev%d", hid->minor);
- if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
- (hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
-
c = "Device";
for (i = 0; i < hid->maxcollection; i++) {
if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
@@ -1475,16 +1480,21 @@ static int hid_probe(struct usb_interfac
usb_make_path(interface_to_usbdev(intf), path, 63);
- printk(": USB HID v%x.%02x %s [%s] on %s\n",
+ printk(KERN_INFO"USB HID v%x.%02x %s [%s] on %s\n",
hid->version >> 8, hid->version & 0xff, c, hid->name, path);
+ hid->module = THIS_MODULE;
+ if (hid_register_device(hid)) {
+ hid_clean(hid);
+ return -ENODEV;
+ }
return 0;
}
static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
struct hid_device *hid = usb_get_intfdata (intf);
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
set_bit(HID_SUSPENDED, &usbhid->iofl);
@@ -1498,7 +1508,7 @@ static int hid_suspend(struct usb_interf
static int hid_resume(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
int status;
clear_bit(HID_SUSPENDED, &usbhid->iofl);
@@ -1525,6 +1535,18 @@ static void hid_post_reset(struct usb_in
hid_resume(intf);
}
+static int usbhid_probe(struct hid_device *hid)
+{
+ int n;
+
+ for (n = 0; hid_blacklist[n].idVendor; n++)
+ if ((hid_blacklist[n].idVendor == hid->vendor) &&
+ (hid_blacklist[n].idProduct == hid->product) &&
+ hid_blacklist[n].quirks == HID_QUIRK_SKIP)
+ return -ENODEV;
+ return hidinput_connect(hid);
+}
+
static struct usb_device_id hid_usb_ids [] = {
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_INTERFACE_CLASS_HID },
@@ -1533,7 +1555,7 @@ static struct usb_device_id hid_usb_ids
MODULE_DEVICE_TABLE (usb, hid_usb_ids);
-static struct usb_driver hid_driver = {
+static struct usb_driver usb_hid_driver = {
.name = "usbhid",
.probe = hid_probe,
.disconnect = hid_disconnect,
@@ -1544,28 +1566,53 @@ static struct usb_driver hid_driver = {
.id_table = hid_usb_ids,
};
+static struct hid_driver hid_usb_driver = {
+ .name = "hidusb",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .probe = usbhid_probe
+};
+
+static struct hid_transport hid_usb_transport = {
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .event = usb_hidinput_input_event,
+ .open = usbhid_open,
+ .close = usbhid_close,
+ .update_busid = usbhid_update_busid,
+ .raw_report = usbhid_raw_report,
+};
+
static int __init hid_init(void)
{
int retval;
- retval = hiddev_init();
+
+ retval = hid_register_transport(&hid_usb_transport);
+ if (retval)
+ goto hidtl_register_fail;
+ retval = hid_register_driver(&hid_usb_driver);
if (retval)
- goto hiddev_init_fail;
- retval = usb_register(&hid_driver);
+ goto hiddrv_register_fail;
+ retval = usb_register(&usb_hid_driver);
if (retval)
goto usb_register_fail;
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
usb_register_fail:
- hiddev_exit();
-hiddev_init_fail:
+ hid_unregister_driver(&hid_usb_driver);
+hiddrv_register_fail:
+ hid_unregister_transport(&hid_usb_transport);
+hidtl_register_fail:
return retval;
}
static void __exit hid_exit(void)
{
- usb_deregister(&hid_driver);
- hiddev_exit();
+ hid_unregister_driver(&hid_usb_driver);
+ hid_unregister_transport(&hid_usb_transport);
+ usb_deregister(&usb_hid_driver);
}
module_init(hid_init);
hidbus.usb.patch
(text/x-patch, 34 KB)
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hiddev.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hiddev.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hiddev.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hiddev.c 2007-04-15 21:29:44.000000000 +0800
@@ -36,6 +36,11 @@
#include <linux/hiddev.h>
#include "usbhid.h"
+#define DRIVER_VERSION "v0.9.0"
+#define DRIVER_AUTHOR "Paul Stewart, Vojtech Pavlik"
+#define DRIVER_DESC "USB HIDDEV driver"
+#define DRIVER_LICENSE "GPL"
+
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define HIDDEV_MINOR_BASE 0
#define HIDDEV_MINORS 256
@@ -48,9 +53,11 @@
struct hiddev {
int exist;
int open;
+ int minor;
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
+ void *private;
};
struct hiddev_list {
@@ -159,7 +166,7 @@ hiddev_lookup_usage(struct hid_device *h
static void hiddev_send_event(struct hid_device *hid,
struct hiddev_usage_ref *uref)
{
- struct hiddev *hiddev = hid->hiddev;
+ struct hiddev *hiddev = hid->private;
struct hiddev_list *list;
list_for_each_entry(list, &hiddev->list, node) {
@@ -179,9 +186,10 @@ static void hiddev_send_event(struct hid
* This is where hid.c calls into hiddev to pass an event that occurred over
* the interrupt pipe
*/
-void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
+static int hiddev_hid_event(struct hid_field *field, struct hid_usage *usage,
+ __s32 value, int interrupt)
{
+ struct hid_device *hid = field->report->device;
unsigned type = field->report_type;
struct hiddev_usage_ref uref;
@@ -196,6 +204,8 @@ void hiddev_hid_event(struct hid_device
uref.value = value;
hiddev_send_event(hid, &uref);
+ /* We always let HID core continue to dispatch this event here. */
+ return 1;
}
EXPORT_SYMBOL_GPL(hiddev_hid_event);
@@ -393,7 +403,7 @@ static int hiddev_ioctl(struct inode *in
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
void __user *user_arg = (void __user *)arg;
int i;
@@ -742,15 +752,15 @@ static struct usb_class_driver hiddev_cl
.minor_base = HIDDEV_MINOR_BASE,
};
-/*
- * This is where hid.c calls us to connect a hid device to the hiddev driver
- */
-int hiddev_connect(struct hid_device *hid)
+static int hiddev_connect(struct hid_device *hid)
{
struct hiddev *hiddev;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct usbhid_device *usbhid = hid->tl_data;
int i;
int retval;
+
+ if (hid->bus != BUS_USB)
+ return -1;
for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type ==
@@ -776,8 +786,8 @@ int hiddev_connect(struct hid_device *hi
hiddev->hid = hid;
hiddev->exist = 1;
- hid->minor = usbhid->intf->minor;
- hid->hiddev = hiddev;
+ hiddev->minor = usbhid->intf->minor;
+ hid->private = hiddev;
hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
@@ -788,15 +798,17 @@ int hiddev_connect(struct hid_device *hi
* This is where hid.c calls us to disconnect a hiddev device from the
* corresponding hid device (usually because the usb device has disconnected)
*/
-static struct usb_class_driver hiddev_class;
-void hiddev_disconnect(struct hid_device *hid)
+static void hiddev_disconnect(struct hid_device *hid)
{
- struct hiddev *hiddev = hid->hiddev;
- struct usbhid_device *usbhid = hid->driver_data;
+ struct hiddev *hiddev = hid->private;
+ struct usbhid_device *usbhid = hid->tl_data;
+
+ if (hid->bus != BUS_USB)
+ return;
hiddev->exist = 0;
- hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
+ hiddev_table[hiddev->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) {
@@ -807,41 +819,34 @@ void hiddev_disconnect(struct hid_device
}
}
-/* Currently this driver is a USB driver. It's not a conventional one in
- * the sense that it doesn't probe at the USB level. Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines. The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us. This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
- const struct usb_device_id *hiddev_info)
-{
- return -ENODEV;
-}
-
+static struct hid_hook hiddev_hook = {
+ .hid_event = hiddev_hid_event,
+};
-static /* const */ struct usb_driver hiddev_driver = {
- .name = "hiddev",
- .probe = hiddev_usbd_probe,
+static struct hid_driver hid_hiddev_driver = {
+ .name = "hiddev",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .probe = hiddev_connect,
+ .remove = hiddev_disconnect,
+ .hook = &hiddev_hook,
};
int __init hiddev_init(void)
{
- return usb_register(&hiddev_driver);
+ set_hid_driver_sticky(&hid_hiddev_driver);
+ return hid_register_driver(&hid_hiddev_driver);
}
-void hiddev_exit(void)
+void __exit hiddev_exit(void)
{
- usb_deregister(&hiddev_driver);
+ hid_unregister_driver(&hid_hiddev_driver);
}
+
+module_init(hiddev_init);
+module_exit(hiddev_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-ff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-ff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-ff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-ff.c 1970-01-01 08:00:00.000000000 +0800
@@ -1,90 +0,0 @@
-/*
- * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
- *
- * Force feedback support for hid devices.
- * Not all hid devices use the same protocol. For example, some use PID,
- * other use their own proprietary procotol.
- *
- * Copyright (c) 2002-2004 Johann Deneux
- */
-
-/*
- * 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 by
- * e-mail - mail your message to <[email protected]>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
- u16 idVendor;
- u16 idProduct;
- int (*init)(struct hid_device*);
-};
-
-/*
- * We try pidff when no other driver is found because PID is the
- * standards compliant way of implementing force feedback in HID.
- * pidff_init() will quickly abort if the device doesn't appear to
- * be a PID device
- */
-static struct hid_ff_initializer inits[] = {
-#ifdef CONFIG_LOGITECH_FF
- { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
- { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
- { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
- { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
- { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
- { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
- { 0x810, 0x0001, hid_plff_init },
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
- { 0x44f, 0xb300, hid_tmff_init },
- { 0x44f, 0xb304, hid_tmff_init },
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
- { 0xc12, 0x0005, hid_zpff_init },
- { 0xc12, 0x0030, hid_zpff_init },
-#endif
- { 0, 0, hid_pidff_init} /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
- struct hid_ff_initializer *init;
- int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
- int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
- for (init = inits; init->idVendor; init++)
- if (init->idVendor == vendor && init->idProduct == product)
- break;
-
- return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-lgff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-lgff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-lgff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-lgff.c 2007-04-15 21:29:54.000000000 +0800
@@ -29,9 +29,10 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/hid.h>
#include "usbhid.h"
+#define DRIVER_VERSION "0.1.0"
+
struct dev_type {
u16 idVendor;
u16 idProduct;
@@ -99,7 +100,7 @@ static int hid_lgff_play(struct input_de
return 0;
}
-int hid_lgff_init(struct hid_device* hid)
+static int hid_lgff_init_device(struct hid_device* hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -148,3 +149,53 @@ int hid_lgff_init(struct hid_device* hid
return 0;
}
+
+static struct usb_device_id hid_lgff_ids[] = {
+ { USB_DEVICE(0x46d, 0xc211) }, /* Logitech Cordless rumble pad */
+ { USB_DEVICE(0x46d, 0xc219) }, /* Logitech Cordless rumble pad 2 */
+ { USB_DEVICE(0x46d, 0xc283) }, /* Logitech Wingman Force 3d */
+ { USB_DEVICE(0x46d, 0xc294) }, /* Logitech Formula Force EX */
+ { USB_DEVICE(0x46d, 0xc295) }, /* Logitech MOMO force wheel */
+ { USB_DEVICE(0x46d, 0xca03) }, /* Logitech MOMO force wheel */
+ {}
+};
+
+MODULE_DEVICE_TABLE (usb, hid_lgff_ids);
+
+static int hid_lgff_match(struct hid_driver *driver, struct hid_device *device)
+{
+ struct usbhid_device *usbhid;
+
+ usbhid = device->tl_data;
+ return (int)usb_match_id(usbhid->intf, hid_lgff_ids);
+}
+
+static int hid_lgff_probe(struct hid_device *device)
+{
+ if (hidinput_connect(device))
+ return -ENODEV;
+ return hid_lgff_init_device(device);
+}
+
+static struct hid_driver hid_lgff_driver = {
+ .name = "hid-lgff",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .match = hid_lgff_match,
+ .probe = hid_lgff_probe,
+};
+
+static int __init hid_lgff_init(void)
+{
+ return hid_register_driver(&hid_lgff_driver);
+}
+
+static void __exit hid_lgff_exit(void)
+{
+ hid_unregister_driver(&hid_lgff_driver);
+}
+
+module_init(hid_lgff_init);
+module_exit(hid_lgff_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-pb.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-pb.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-pb.c 1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-pb.c 2007-04-15 21:30:02.000000000 +0800
@@ -0,0 +1,334 @@
+/*
+ * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006-2007 Jiri Kosina
+ *
+ * iBook/PowerBook special keys support.
+ */
+
+/*
+ * 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/spinlock.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+
+#include "usbhid.h"
+
+#define DRIVER_VERSION "0.1.0"
+
+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)");
+
+#define USB_VENDOR_ID_APPLE 0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IR 0x8240
+
+#define USB_VENDOR_ID_CHERRY 0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
+
+struct hids_pb_data {
+ unsigned long pressed_fn[NBITS(KEY_MAX)];
+ unsigned long pressed_numlock[NBITS(KEY_MAX)];
+};
+
+static const struct pb_feature {
+ __u16 idProduct;
+ unsigned quirks;
+} pb_feature_list[] = {
+ { USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_IGNORE_MOUSE },
+ { USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_IGNORE_MOUSE },
+ { 0, 0 }
+};
+
+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 hids_pb_hid_event(struct hid_field *field, struct hid_usage *usage,
+ __s32 value, int interrupt)
+{
+ struct hidinput_key_translation *trans;
+ struct hid_input *hidinput = field->hidinput;
+ struct hid_device *hid = field->report->device;
+ struct hids_pb_data *pb_data = hid->driver->private;
+
+ if (!pb_data)
+ return -1;
+
+ if (usage->code == KEY_FN) {
+ if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
+ else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+
+ input_event(hidinput->input, usage->type, usage->code, value);
+ return 0;
+ }
+
+ if (hid_pb_fnmode) {
+ int do_translate;
+
+ trans = find_translation(powerbook_fn_keys, usage->code);
+ if (trans) {
+ if (test_bit(usage->code, pb_data->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, pb_data->pressed_fn);
+ else
+ clear_bit(usage->code, pb_data->pressed_fn);
+
+ input_event(hidinput->input, usage->type,
+ trans->to, value);
+
+ return 0;
+ }
+ }
+
+ if (test_bit(usage->code, pb_data->pressed_numlock) ||
+ test_bit(LED_NUML, hidinput->input->led)) {
+ trans = find_translation(powerbook_numlock_keys, usage->code);
+
+ if (trans) {
+ if (value)
+ set_bit(usage->code, pb_data->pressed_numlock);
+ else
+ clear_bit(usage->code, pb_data->pressed_numlock);
+
+ input_event(hidinput->input, usage->type, trans->to, value);
+ }
+ return 0;
+ }
+ }
+
+ if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
+ trans = find_translation(powerbook_iso_keyboard, usage->code);
+ if (trans) {
+ input_event(hidinput->input, usage->type, trans->to, value);
+ return 0;
+ }
+ }
+
+ hidinput_hid_event(hid, field, usage, value);
+ 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);
+}
+
+static struct usb_device_id hids_pb_ids[] = {
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ {}
+};
+MODULE_DEVICE_TABLE (usb, hids_pb_ids);
+
+static int hid_pb_match(struct hid_driver *driver, struct hid_device *device)
+{
+ struct usbhid_device *usbhid;
+
+ if (!driver || !device)
+ return 0;
+ usbhid = device->tl_data;
+ return !!usb_match_id(usbhid->intf, hids_pb_ids);
+}
+
+static int hid_pb_probe(struct hid_device *dev)
+{
+ int i;
+ struct hid_driver *drv = dev->driver;
+
+ for (i=0; pb_feature_list[i].quirks; ++i) {
+ if (pb_feature_list[i].idProduct == dev->product)
+ dev->quirks = pb_feature_list[i].quirks;
+ }
+ drv->private = kzalloc(sizeof(struct hids_pb_data), GFP_KERNEL);
+ if (!drv->private)
+ return 0;
+ return hidinput_connect(dev);
+}
+
+static void hids_pb_setup_usage(struct hid_field *field, struct hid_usage *usage)
+{
+ unsigned long *bit;
+ struct input_dev* input = field->hidinput->input;
+
+ if (0x003 != (usage->hid & HID_USAGE))
+ return;
+ usage->code = KEY_FN;
+ usage->type = EV_KEY;
+ bit = input->keybit;
+ clear_bit(KEY_FN, input->keybit);
+ hidinput_pb_setup(input);
+}
+
+static struct hid_hook hid_pb_hook = {
+ .hid_event = hids_pb_hid_event,
+ .setup_usage = hids_pb_setup_usage,
+};
+
+static struct hid_driver hids_pb_driver = {
+ .name = "hid-pb",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .match = hid_pb_match,
+ .probe = hid_pb_probe,
+ .hook = &hid_pb_hook,
+};
+
+static int __init hids_pb_init(void)
+{
+ return hid_register_driver(&hids_pb_driver);
+}
+
+static void __exit hids_pb_exit(void)
+{
+ hid_unregister_driver(&hids_pb_driver);
+}
+
+module_init(hids_pb_init);
+module_exit(hids_pb_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-pidff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-pidff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-pidff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-pidff.c 2007-04-15 21:30:14.000000000 +0800
@@ -27,10 +27,10 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/hid.h>
-
#include "usbhid.h"
+#define DRIVER_VERSION "0.1.0"
+
#define PID_EFFECTS_MAX 64
/* Report usage table used to put reports into an array */
@@ -1236,7 +1236,7 @@ static int pidff_check_autocenter(struct
/*
* Check if the device is PID and initialize it
*/
-int hid_pidff_init(struct hid_device *hid)
+int hid_pidff_init_device(struct hid_device *hid)
{
struct pidff_device *pidff;
struct hid_input *hidinput = list_entry(hid->inputs.next,
@@ -1329,3 +1329,33 @@ int hid_pidff_init(struct hid_device *hi
kfree(pidff);
return error;
}
+
+static int hid_pidff_probe(struct hid_device *device)
+{
+ if (hidinput_connect(device))
+ return -ENODEV;
+ return hid_pidff_init_device(device);
+}
+
+static struct hid_driver hid_pidff_driver = {
+ .name = "hid-pidff",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .probe = hid_pidff_probe,
+};
+
+static int __init hid_pidff_init(void)
+{
+ set_hid_driver_sticky(&hid_pidff_driver);
+ return hid_register_driver(&hid_pidff_driver);
+}
+
+static void __exit hid_pidff_exit(void)
+{
+ hid_unregister_driver(&hid_pidff_driver);
+}
+
+module_init(hid_pidff_init);
+module_exit(hid_pidff_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-plff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-plff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-plff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-plff.c 2007-04-15 21:30:26.000000000 +0800
@@ -27,9 +27,10 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/hid.h>
#include "usbhid.h"
+#define DRIVER_VERSION "0.1.0"
+
struct plff_device {
struct hid_report *report;
};
@@ -56,7 +57,7 @@ static int hid_plff_play(struct input_de
return 0;
}
-int hid_plff_init(struct hid_device *hid)
+int hid_plff_init_device(struct hid_device *hid)
{
struct plff_device *plff;
struct hid_report *report;
@@ -127,3 +128,48 @@ int hid_plff_init(struct hid_device *hid
return 0;
}
+
+static struct usb_device_id hid_plff_ids[] = {
+ { USB_DEVICE(0x810, 0x0001) },
+ {}
+};
+
+MODULE_DEVICE_TABLE (usb, hid_plff_ids);
+
+static int hid_plff_match(struct hid_driver *driver, struct hid_device *device)
+{
+ struct usbhid_device *usbhid;
+
+ usbhid = device->tl_data;
+ return (int)usb_match_id(usbhid->intf, hid_plff_ids);
+}
+
+static int hid_plff_probe(struct hid_device *device)
+{
+ if (hidinput_connect(device))
+ return -ENODEV;
+ return hid_plff_init_device(device);
+}
+
+static struct hid_driver hid_plff_driver = {
+ .name = "hid-plff",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .match = hid_plff_match,
+ .probe = hid_plff_probe,
+};
+
+static int __init hid_plff_init(void)
+{
+ return hid_register_driver(&hid_plff_driver);
+}
+
+static void __exit hid_plff_exit(void)
+{
+ hid_unregister_driver(&hid_plff_driver);
+}
+
+module_init(hid_plff_init);
+module_exit(hid_plff_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-tmff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-tmff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-tmff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-tmff.c 2007-04-15 21:30:35.000000000 +0800
@@ -32,9 +32,10 @@
#undef DEBUG
#include <linux/usb.h>
-#include <linux/hid.h>
#include "usbhid.h"
+#define DRIVER_VERSION "0.1.0"
+
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
@@ -76,7 +77,7 @@ static int hid_tmff_play(struct input_de
return 0;
}
-int hid_tmff_init(struct hid_device *hid)
+int hid_tmff_init_device(struct hid_device *hid)
{
struct tmff_device *tmff;
struct list_head *pos;
@@ -145,3 +146,48 @@ int hid_tmff_init(struct hid_device *hid
return 0;
}
+
+static struct usb_device_id hid_tmff_ids[] = {
+ { USB_DEVICE(0x44f, 0xb304) },
+ {}
+};
+
+MODULE_DEVICE_TABLE (usb, hid_tmff_ids);
+
+static int hid_tmff_match(struct hid_driver *driver, struct hid_device *device)
+{
+ struct usbhid_device *usbhid;
+
+ usbhid = device->tl_data;
+ return (int)usb_match_id(usbhid->intf, hid_tmff_ids);
+}
+
+static int hid_tmff_probe(struct hid_device *device)
+{
+ if (hidinput_connect(device))
+ return -ENODEV;
+ return hid_tmff_init_device(device);
+}
+
+static struct hid_driver hid_tmff_driver = {
+ .name = "hid-tmff",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .match = hid_tmff_match,
+ .probe = hid_tmff_probe,
+};
+
+static int __init hid_tmff_init(void)
+{
+ return hid_register_driver(&hid_tmff_driver);
+}
+
+static void __exit hid_tmff_exit(void)
+{
+ hid_unregister_driver(&hid_tmff_driver);
+}
+
+module_init(hid_tmff_init);
+module_exit(hid_tmff_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-zpff.c linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-zpff.c
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/hid-zpff.c 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/hid-zpff.c 2007-04-15 21:30:44.000000000 +0800
@@ -27,9 +27,10 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/hid.h>
#include "usbhid.h"
+#define DRIVER_VERSION "0.1.0"
+
struct zpff_device {
struct hid_report *report;
};
@@ -62,7 +63,7 @@ static int hid_zpff_play(struct input_de
return 0;
}
-int hid_zpff_init(struct hid_device *hid)
+int hid_zpff_init_device(struct hid_device *hid)
{
struct zpff_device *zpff;
struct hid_report *report;
@@ -109,3 +110,50 @@ int hid_zpff_init(struct hid_device *hid
return 0;
}
+
+static struct usb_device_id hid_zpff_ids[] = {
+ { USB_DEVICE(0x46d, 0x0005) },
+ { USB_DEVICE(0xc12, 0x0030) },
+ {}
+};
+
+MODULE_DEVICE_TABLE (usb, hid_zpff_ids);
+
+static int hid_zpff_match(struct hid_driver *driver, struct hid_device *device)
+{
+ struct usbhid_device *usbhid;
+
+ usbhid = device->tl_data;
+ return (int)usb_match_id(usbhid->intf, hid_zpff_ids);
+}
+
+static int hid_zpff_probe(struct hid_device *device)
+{
+ if (hidinput_connect(device))
+ return -ENODEV;
+ return hid_zpff_init_device(device);
+}
+
+
+static struct hid_driver hid_zpff_driver = {
+ .name = "hid-zpff",
+ .version = DRIVER_VERSION,
+ .bus = BUS_USB,
+ .module = THIS_MODULE,
+ .match = hid_zpff_match,
+ .probe = hid_zpff_probe,
+};
+
+static int __init hid_zpff_init(void)
+{
+ return hid_register_driver(&hid_zpff_driver);
+}
+
+static void __exit hid_zpff_exit(void)
+{
+ hid_unregister_driver(&hid_zpff_driver);
+}
+
+module_init(hid_zpff_init);
+module_exit(hid_zpff_exit);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/Kconfig linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/Kconfig
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/Kconfig 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/Kconfig 2007-04-10 10:24:51.000000000 +0800
@@ -24,8 +24,8 @@ config USB_HID
comment "Input core support is needed for USB HID input layer or HIDBP support"
depends on USB_HID && INPUT=n
-config USB_HIDINPUT_POWERBOOK
- bool "Enable support for iBook/PowerBook special keys"
+config POWERBOOK
+ tristate "Enable support for iBook/PowerBook special keys"
default n
depends on USB_HID
help
@@ -34,29 +34,17 @@ config USB_HIDINPUT_POWERBOOK
If unsure, say N.
-config HID_FF
- bool "Force feedback support (EXPERIMENTAL)"
- depends on USB_HID && EXPERIMENTAL
- help
- Say Y here is you want force feedback support for a few HID devices.
- See below for a list of supported devices.
-
- See <file:Documentation/input/ff.txt> for a description of the force
- feedback API.
-
- If unsure, say N.
-
config HID_PID
- bool "PID device support"
- depends on HID_FF
+ tristate "PID device support"
+ depends on USB_HID
help
Say Y here if you have a PID-compliant device and wish to enable force
feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
devices.
config LOGITECH_FF
- bool "Logitech devices support"
- depends on HID_FF
+ tristate "Logitech devices support"
+ depends on USB_HID
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have one of these devices:
@@ -71,16 +59,16 @@ config LOGITECH_FF
force feedback.
config PANTHERLORD_FF
- bool "PantherLord USB/PS2 2in1 Adapter support"
- depends on HID_FF
+ tristate "PantherLord USB/PS2 2in1 Adapter support"
+ depends on USB_HID
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
to enable force feedback support for it.
config THRUSTMASTER_FF
- bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
- depends on HID_FF && EXPERIMENTAL
+ tristate "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+ depends on USB_HID && EXPERIMENTAL
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
@@ -89,15 +77,15 @@ config THRUSTMASTER_FF
force feedback.
config ZEROPLUS_FF
- bool "Zeroplus based game controller support"
- depends on HID_FF
+ tristate "Zeroplus based game controller support"
+ depends on USB_HID
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have a Zeroplus based game controller and want to
enable force feedback for it.
config USB_HIDDEV
- bool "/dev/hiddev raw HID device support"
+ tristate "/dev/hiddev raw HID device support"
depends on USB_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/usbhid/Makefile linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/Makefile
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/Makefile 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/Makefile 2007-04-17 09:23:33.000000000 +0800
@@ -6,29 +6,13 @@
usbhid-objs := hid-core.o
# Optional parts of multipart objects.
-
-ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-objs += hiddev.o
-endif
-ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += hid-pidff.o
-endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
- usbhid-objs += hid-lgff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
- usbhid-objs += hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
- usbhid-objs += hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
- usbhid-objs += hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
- usbhid-objs += hid-ff.o
-endif
-
+obj-$(CONFIG_HID_PID) += hid-pidff.o
+obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
+obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+obj-$(CONFIG_POWERBOOK) += hid-pb.o
+obj-$(CONFIG_LOGITECH_FF) += hid-lgff.o
+obj-$(CONFIG_PANTHERLORD_FF) += hid-plff.o
+obj-$(CONFIG_USB_HIDDEV) += hiddev.o
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o
diff -Naurp linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/usbhid.h linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/usbhid.h
--- linux-2.6.21-rc6-mm1.orig/drivers/hid/usbhid/usbhid.h 2007-04-10 09:16:46.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/drivers/hid/usbhid/usbhid.h 2007-04-10 10:24:51.000000000 +0800
@@ -30,6 +30,9 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/input.h>
+#include <linux/wait.h>
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
/* API provided by hid-core.c for USB HID drivers */
int usbhid_wait_io(struct hid_device* hid);
@@ -77,6 +80,7 @@ struct usbhid_device {
unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */
struct work_struct reset_work; /* Task context for resets */
+ wait_queue_head_t wait;
};
hidbus.bluetooth.patch
(text/x-patch, 4.9 KB)
diff -Naurp linux-2.6.21-rc6-mm1.orig/net/bluetooth/hidp/core.c linux-2.6.21-rc6-mm1.new/net/bluetooth/hidp/core.c
--- linux-2.6.21-rc6-mm1.orig/net/bluetooth/hidp/core.c 2007-04-10 09:16:51.000000000 +0800
+++ linux-2.6.21-rc6-mm1.new/net/bluetooth/hidp/core.c 2007-04-17 09:19:27.000000000 +0800
@@ -54,6 +54,7 @@
#define VERSION "1.2"
+static DECLARE_WAIT_QUEUE_HEAD(hidp_session_clean_barrier);
static DECLARE_RWSEM(hidp_session_sem);
static LIST_HEAD(hidp_session_list);
@@ -78,6 +79,15 @@ static unsigned char hidp_keycode[256] =
static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+static void hidp_update_busid(struct hid_device *dev)
+{
+ static atomic_t hidp_hiddev_idx = ATOMIC_INIT(-1);
+
+ snprintf(dev->device.bus_id, BUS_ID_SIZE, "B:%04x:%04x:%d",
+ dev->vendor, dev->product,
+ atomic_add_return(1, &hidp_hiddev_idx));
+}
+
static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
{
struct hidp_session *session;
@@ -176,7 +186,7 @@ static inline int hidp_queue_event(struc
static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = dev->private;
- struct hidp_session *session = hid->driver_data;
+ struct hidp_session *session = hid->tl_data;
return hidp_queue_event(session, dev, type, code, value);
}
@@ -544,6 +554,11 @@ static int hidp_session(void *arg)
if (session->hid) {
vendor = session->hid->vendor;
product = session->hid->product;
+ session->hid->module = THIS_MODULE;
+ if (hid_register_device(session->hid)) {
+ hid_free_device(session->hid);
+ session->hid = NULL;
+ }
}
daemonize("khidpd_%04x%04x", vendor, product);
@@ -598,14 +613,17 @@ static int hidp_session(void *arg)
}
if (session->hid) {
- if (session->hid->claimed & HID_CLAIMED_INPUT)
- hidinput_disconnect(session->hid);
+ hid_unregister_device(session->hid);
hid_free_device(session->hid);
}
up_write(&hidp_session_sem);
kfree(session);
+
+ if (list_empty(&hidp_session_list))
+ wake_up(&hidp_session_clean_barrier);
+
return 0;
}
@@ -711,7 +729,7 @@ static inline void hidp_setup_hid(struct
baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
- hid->driver_data = session;
+ hid->tl_data = session;
hid->country = req->country;
@@ -726,11 +744,6 @@ static inline void hidp_setup_hid(struct
hid->dev = hidp_get_device(session);
- hid->hid_open = hidp_open;
- hid->hid_close = hidp_close;
-
- hid->hidinput_input_event = hidp_hidinput_event;
-
hidp_setup_quirks(hid);
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
@@ -738,11 +751,6 @@ static inline void hidp_setup_hid(struct
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
hidp_send_report(session, report);
-
- if (hidinput_connect(hid) == 0) {
- hid->claimed |= HID_CLAIMED_INPUT;
- hid_ff_init(hid);
- }
}
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -868,6 +876,10 @@ failed:
kfree(session->input);
kfree(session);
+
+ if (list_empty(&hidp_session_list))
+ wake_up(&hidp_session_clean_barrier);
+
return err;
}
@@ -951,8 +963,57 @@ int hidp_get_conninfo(struct hidp_connin
return err;
}
+static struct hid_driver hid_bt_driver = {
+ .name = "hidbt",
+ .version = "0.9.0",
+ .bus = BUS_BLUETOOTH,
+ .module = THIS_MODULE,
+ .match = NULL, /* default match any bluetooth hidp device. */
+ .probe = NULL, /* default is hidinput_connect() */
+ .remove = NULL, /* default is hidinput_disconnect() */
+};
+
+static struct hid_transport hid_bt_transport = {
+ .bus = BUS_BLUETOOTH,
+ .event = hidp_hidinput_event,
+ .open = hidp_open,
+ .close = hidp_close,
+ .update_busid = hidp_update_busid,
+ .module = THIS_MODULE,
+};
+
+static int is_hidp_session_list_empty(void)
+{
+ int ret;
+
+ down_read(&hidp_session_sem);
+ ret = list_empty(&hidp_session_list);
+ up_read(&hidp_session_sem);
+ return ret;
+}
+
+static void hidp_session_clean(void)
+{
+ struct hidp_session *session;
+
+ down_read(&hidp_session_sem);
+ list_for_each_entry(session, &hidp_session_list, list) {
+ atomic_inc(&session->terminate);
+ hidp_schedule(session);
+ }
+ up_read(&hidp_session_sem);
+}
+
+
static int __init hidp_init(void)
{
+ if (hid_register_transport(&hid_bt_transport))
+ return -ENODEV;
+ if (hid_register_driver(&hid_bt_driver)) {
+ hid_unregister_transport(&hid_bt_transport);
+ return -ENODEV;
+ }
+
l2cap_load();
BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
@@ -962,6 +1023,11 @@ static int __init hidp_init(void)
static void __exit hidp_exit(void)
{
+ hidp_session_clean();
+ wait_event(hidp_session_clean_barrier, is_hidp_session_list_empty());
+
+ hid_unregister_transport(&hid_bt_transport);
+ hid_unregister_driver(&hid_bt_driver);
hidp_cleanup_sockets();
}