summaryrefslogtreecommitdiffstats
path: root/include/linux/hid.h
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2008-10-22 23:57:26 -0400
committerLen Brown <len.brown@intel.com>2008-10-23 00:11:07 -0400
commit057316cc6a5b521b332a1d7ccc871cd60c904c74 (patch)
tree4333e608da237c73ff69b10878025cca96dcb4c8 /include/linux/hid.h
parent3e2dab9a1c2deb03c311eb3f83466009147ed4d3 (diff)
parent2515ddc6db8eb49a79f0fe5e67ff09ac7c81eab4 (diff)
Merge branch 'linus' into test
Conflicts: MAINTAINERS arch/x86/kernel/acpi/boot.c arch/x86/kernel/acpi/sleep.c drivers/acpi/Kconfig drivers/pnp/Makefile drivers/pnp/quirks.c Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'include/linux/hid.h')
-rw-r--r--include/linux/hid.h373
1 files changed, 298 insertions, 75 deletions
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ac4e678a04e..f13bca2dd53 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -67,6 +67,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/list.h>
+#include <linux/mod_devicetable.h> /* hid_device_id */
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/input.h>
@@ -246,6 +247,19 @@ struct hid_item {
#define HID_FEATURE_REPORT 2
/*
+ * HID connect requests
+ */
+
+#define HID_CONNECT_HIDINPUT 0x01
+#define HID_CONNECT_HIDINPUT_FORCE 0x02
+#define HID_CONNECT_HIDRAW 0x04
+#define HID_CONNECT_HIDDEV 0x08
+#define HID_CONNECT_HIDDEV_FORCE 0x10
+#define HID_CONNECT_FF 0x20
+#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
+ HID_CONNECT_HIDDEV|HID_CONNECT_FF)
+
+/*
* HID device quirks.
*/
@@ -256,48 +270,11 @@ struct hid_item {
#define HID_QUIRK_INVERT 0x00000001
#define HID_QUIRK_NOTOUCH 0x00000002
-#define HID_QUIRK_IGNORE 0x00000004
#define HID_QUIRK_NOGET 0x00000008
-#define HID_QUIRK_HIDDEV 0x00000010
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200
-#define HID_QUIRK_MIGHTYMOUSE 0x00000400
-#define HID_QUIRK_APPLE_HAS_FN 0x00000800
-#define HID_QUIRK_APPLE_FN_ON 0x00001000
-#define HID_QUIRK_INVERT_HWHEEL 0x00002000
-#define HID_QUIRK_APPLE_ISO_KEYBOARD 0x00004000
-#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00008000
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
-#define HID_QUIRK_IGNORE_MOUSE 0x00020000
-#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000
-#define HID_QUIRK_DUPLICATE_USAGES 0x00080000
-#define HID_QUIRK_RESET_LEDS 0x00100000
-#define HID_QUIRK_HIDINPUT 0x00200000
-#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000
-#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000
-#define HID_QUIRK_IGNORE_HIDINPUT 0x01000000
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
-#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
-#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
-#define HID_QUIRK_APPLE_NUMLOCK_EMULATION 0x20000000
-
-/*
- * Separate quirks for runtime report descriptor fixup
- */
-
-#define HID_QUIRK_RDESC_CYMOTION 0x00000001
-#define HID_QUIRK_RDESC_LOGITECH 0x00000002
-#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004
-#define HID_QUIRK_RDESC_PETALYNX 0x00000008
-#define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010
-#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020
-#define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040
-#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080
-#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100
/*
* This is the global environment of the parser. This information is
@@ -411,12 +388,21 @@ struct hid_report_enum {
struct hid_control_fifo {
unsigned char dir;
struct hid_report *report;
+ char *raw_report;
+};
+
+struct hid_output_fifo {
+ struct hid_report *report;
+ char *raw_report;
};
#define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 2
#define HID_CLAIMED_HIDRAW 4
+#define HID_STAT_ADDED 1
+#define HID_STAT_PARSED 2
+
#define HID_CTRL_RUNNING 1
#define HID_OUT_RUNNING 2
#define HID_IN_RUNNING 3
@@ -431,22 +417,28 @@ struct hid_input {
struct input_dev *input;
};
+struct hid_driver;
+struct hid_ll_driver;
+
struct hid_device { /* device report descriptor */
- __u8 *rdesc;
+ __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 */
+ __u16 bus; /* BUS ID */
+ __u32 vendor; /* Vendor ID */
+ __u32 product; /* Product ID */
+ __u32 version; /* HID version */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
- struct device *dev; /* device */
+ struct device dev; /* device */
+ struct hid_driver *driver;
+ struct hid_ll_driver *ll_driver;
+ unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
@@ -462,26 +454,29 @@ struct hid_device { /* device report descriptor */
void *driver_data;
- __s32 delayed_value; /* For A4 Tech mice hwheel quirk */
-
- /* 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 *);
+ /* temporary hid_ff handling (until moved to the drivers) */
+ int (*ff_init)(struct hid_device *);
/* hiddev event handler */
+ int (*hiddev_connect)(struct hid_device *, unsigned int);
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 apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
- unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)];
-#endif
};
+static inline void *hid_get_drvdata(struct hid_device *hdev)
+{
+ return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
+{
+ dev_set_drvdata(&hdev->dev, data);
+}
+
#define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4
@@ -510,6 +505,107 @@ struct hid_descriptor {
struct hid_class_descriptor desc[1];
} __attribute__ ((packed));
+#define HID_DEVICE(b, ven, prod) \
+ .bus = (b), \
+ .vendor = (ven), .product = (prod)
+
+#define HID_USB_DEVICE(ven, prod) HID_DEVICE(BUS_USB, ven, prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod) HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+
+#define HID_REPORT_ID(rep) \
+ .report_type = (rep)
+#define HID_USAGE_ID(uhid, utype, ucode) \
+ .usage_hid = (uhid), .usage_type = (utype), .usage_code = (ucode)
+/* we don't want to catch types and codes equal to 0 */
+#define HID_TERMINATOR (HID_ANY_ID - 1)
+
+struct hid_report_id {
+ __u32 report_type;
+};
+struct hid_usage_id {
+ __u32 usage_hid;
+ __u32 usage_type;
+ __u32 usage_code;
+};
+
+/**
+ * struct hid_driver
+ * @name: driver name (e.g. "Footech_bar-wheel")
+ * @id_table: which devices is this driver for (must be non-NULL for probe
+ * to be called)
+ * @probe: new device inserted
+ * @remove: device removed (NULL if not a hot-plug capable driver)
+ * @report_table: on which reports to call raw_event (NULL means all)
+ * @raw_event: if report in report_table, this hook is called (NULL means nop)
+ * @usage_table: on which events to call event (NULL means all)
+ * @event: if usage in usage_table, this hook is called (NULL means nop)
+ * @report_fixup: called before report descriptor parsing (NULL means nop)
+ * @input_mapping: invoked on input registering before mapping an usage
+ * @input_mapped: invoked on input registering after mapping an usage
+ *
+ * raw_event and event should return 0 on no action performed, 1 when no
+ * further processing should be done and negative on error
+ *
+ * input_mapping shall return a negative value to completely ignore this usage
+ * (e.g. doubled or invalid usage), zero to continue with parsing of this
+ * usage by generic code (no special handling needed) or positive to skip
+ * generic parsing (needed special handling which was done in the hook already)
+ * input_mapped shall return negative to inform the layer that this usage
+ * should not be considered for further processing or zero to notify that
+ * no processing was performed and should be done in a generic manner
+ * Both these functions may be NULL which means the same behavior as returning
+ * zero from them.
+ */
+struct hid_driver {
+ char *name;
+ const struct hid_device_id *id_table;
+
+ int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
+ void (*remove)(struct hid_device *dev);
+
+ const struct hid_report_id *report_table;
+ int (*raw_event)(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size);
+ const struct hid_usage_id *usage_table;
+ int (*event)(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value);
+
+ void (*report_fixup)(struct hid_device *hdev, __u8 *buf,
+ unsigned int size);
+
+ int (*input_mapping)(struct hid_device *hdev,
+ struct hid_input *hidinput, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max);
+ int (*input_mapped)(struct hid_device *hdev,
+ struct hid_input *hidinput, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max);
+/* private: */
+ struct device_driver driver;
+};
+
+/**
+ * hid_ll_driver - low level driver callbacks
+ * @start: called on probe to start the device
+ * @stop: called on remove
+ * @open: called by input layer on open
+ * @close: called by input layer on close
+ * @hidinput_input_event: event input event (e.g. ff or leds)
+ * @parse: this method is called only once to parse the device data,
+ * shouldn't allocate anything to not leak memory
+ */
+struct hid_ll_driver {
+ int (*start)(struct hid_device *hdev);
+ void (*stop)(struct hid_device *hdev);
+
+ int (*open)(struct hid_device *hdev);
+ void (*close)(struct hid_device *hdev);
+
+ int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
+ unsigned int code, int value);
+
+ int (*parse)(struct hid_device *hdev);
+};
+
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
@@ -520,43 +616,157 @@ struct hid_descriptor {
extern int hid_debug;
#endif
+extern int hid_add_device(struct hid_device *);
+extern void hid_destroy_device(struct hid_device *);
+
+extern int __must_check __hid_register_driver(struct hid_driver *,
+ struct module *, const char *mod_name);
+static inline int __must_check hid_register_driver(struct hid_driver *driver)
+{
+ return __hid_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
+}
+extern void hid_unregister_driver(struct hid_driver *);
+
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
+extern int hidinput_connect(struct hid_device *hid, unsigned int force);
extern void hidinput_disconnect(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *, int type, u8 *, int, int);
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
-int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
void hid_output_report(struct hid_report *report, __u8 *data);
-void hid_free_device(struct hid_device *device);
-struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+struct hid_device *hid_allocate_device(void);
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_connect(struct hid_device *hid, unsigned int connect_mask);
+
+/**
+ * hid_map_usage - map usage input bits
+ *
+ * @hidinput: hidinput which we are interested in
+ * @usage: usage to fill in
+ * @bit: pointer to input->{}bit (out parameter)
+ * @max: maximal valid usage->code to consider later (out parameter)
+ * @type: input event type (EV_KEY, EV_REL, ...)
+ * @c: code which corresponds to this usage and type
+ */
+static inline void hid_map_usage(struct hid_input *hidinput,
+ struct hid_usage *usage, unsigned long **bit, int *max,
+ __u8 type, __u16 c)
+{
+ struct input_dev *input = hidinput->input;
+
+ usage->type = type;
+ usage->code = c;
+
+ switch (type) {
+ case EV_ABS:
+ *bit = input->absbit;
+ *max = ABS_MAX;
+ break;
+ case EV_REL:
+ *bit = input->relbit;
+ *max = REL_MAX;
+ break;
+ case EV_KEY:
+ *bit = input->keybit;
+ *max = KEY_MAX;
+ break;
+ case EV_LED:
+ *bit = input->ledbit;
+ *max = LED_MAX;
+ break;
+ }
+}
+
+/**
+ * hid_map_usage_clear - map usage input bits and clear the input bit
+ *
+ * The same as hid_map_usage, except the @c bit is also cleared in supported
+ * bits (@bit).
+ */
+static inline void hid_map_usage_clear(struct hid_input *hidinput,
+ struct hid_usage *usage, unsigned long **bit, int *max,
+ __u8 type, __u16 c)
+{
+ hid_map_usage(hidinput, usage, bit, max, type, c);
+ clear_bit(c, *bit);
+}
+
+/**
+ * hid_parse - parse HW reports
+ *
+ * @hdev: hid device
+ *
+ * Call this from probe after you set up the device (if needed). Your
+ * report_fixup will be called (if non-NULL) after reading raw report from
+ * device before passing it to hid layer for real parsing.
+ */
+static inline int __must_check hid_parse(struct hid_device *hdev)
+{
+ int ret;
+
+ if (hdev->status & HID_STAT_PARSED)
+ return 0;
+
+ ret = hdev->ll_driver->parse(hdev);
+ if (!ret)
+ hdev->status |= HID_STAT_PARSED;
+
+ return ret;
+}
+
+/**
+ * hid_hw_start - start underlaying HW
+ *
+ * @hdev: hid device
+ * @connect_mask: which outputs to connect, see HID_CONNECT_*
+ *
+ * Call this in probe function *after* hid_parse. This will setup HW buffers
+ * and start the device (if not deffered to device open). hid_hw_stop must be
+ * called if this was successfull.
+ */
+static inline int __must_check hid_hw_start(struct hid_device *hdev,
+ unsigned int connect_mask)
+{
+ int ret = hdev->ll_driver->start(hdev);
+ if (ret || !connect_mask)
+ return ret;
+ ret = hid_connect(hdev, connect_mask);
+ if (ret)
+ hdev->ll_driver->stop(hdev);
+ return ret;
+}
+
+/**
+ * hid_hw_stop - stop underlaying HW
+ *
+ * @hdev: hid device
+ *
+ * This is usually called from remove function or from probe when something
+ * failed and hid_hw_start was called already.
+ */
+static inline void hid_hw_stop(struct hid_device *hdev)
+{
+ hdev->ll_driver->stop(hdev);
+}
+
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+ int interrupt);
+
+extern int hid_generic_init(void);
+extern void hid_generic_exit(void);
/* HID quirks API */
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
int usbhid_quirks_init(char **quirks_param);
void usbhid_quirks_exit(void);
-void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
-
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
+void usbhid_set_leds(struct hid_device *hid);
-int hid_lgff_init(struct hid_device *hid);
-int hid_lg2ff_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
-
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#define hid_pidff_init NULL
#endif
#ifdef CONFIG_HID_DEBUG
@@ -572,10 +782,23 @@ dbg_hid(const char *fmt, ...)
return 0;
}
#define dbg_hid_line dbg_hid
-#endif
+#endif /* HID_DEBUG */
#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
__FILE__ , ## arg)
-#endif
+#endif /* HID_FF */
+
+#ifdef CONFIG_HID_COMPAT
+#define HID_COMPAT_LOAD_DRIVER(name) \
+void hid_compat_##name(void) { } \
+EXPORT_SYMBOL(hid_compat_##name)
+#else
+#define HID_COMPAT_LOAD_DRIVER(name)
+#endif /* HID_COMPAT */
+#define HID_COMPAT_CALL_DRIVER(name) do { \
+ extern void hid_compat_##name(void); \
+ hid_compat_##name(); \
+} while (0)
+
#endif