[PATCH 4/5]:hidbus prototype 070409:usbhid drivers

"Li Yu" <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
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 <johann.deneux@xxxxxxxx>
- */
-
-#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 <vojtech@xxxxxx>, 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;
 
 };

-------------------------------------------------------------------------
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.