]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/hid/hid-core.c
ide-cd: fix leftover data BUG
[linux-2.6-omap-h63xx.git] / drivers / hid / hid-core.c
index 6ec04e79f6856c0340f20a31f0b08bb9b6afeeb6..d73a768e176e97becbcad37d5f26372d611ee482 100644 (file)
 #include <linux/input.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
+#include <linux/sched.h>
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
 #include <linux/hid-debug.h>
+#include <linux/hidraw.h>
 
 /*
  * Version Information
 #define DRIVER_DESC "HID core driver"
 #define DRIVER_LICENSE "GPL"
 
+#ifdef CONFIG_HID_DEBUG
+int hid_debug = 0;
+module_param_named(debug, hid_debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off");
+EXPORT_SYMBOL_GPL(hid_debug);
+#endif
+
 /*
  * Register a new report for a device.
  */
@@ -78,7 +87,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
        struct hid_field *field;
 
        if (report->maxfield == HID_MAX_FIELDS) {
-               dbg("too many fields in report");
+               dbg_hid("too many fields in report\n");
                return NULL;
        }
 
@@ -106,7 +115,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
        usage = parser->local.usage[0];
 
        if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
-               dbg("collection stack overflow");
+               dbg_hid("collection stack overflow\n");
                return -1;
        }
 
@@ -114,7 +123,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
                collection = kmalloc(sizeof(struct hid_collection) *
                                parser->device->collection_size * 2, GFP_KERNEL);
                if (collection == NULL) {
-                       dbg("failed to reallocate collection array");
+                       dbg_hid("failed to reallocate collection array\n");
                        return -1;
                }
                memcpy(collection, parser->device->collection,
@@ -150,7 +159,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
 static int close_collection(struct hid_parser *parser)
 {
        if (!parser->collection_stack_ptr) {
-               dbg("collection stack underflow");
+               dbg_hid("collection stack underflow\n");
                return -1;
        }
        parser->collection_stack_ptr--;
@@ -178,7 +187,7 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
 static int hid_add_usage(struct hid_parser *parser, unsigned usage)
 {
        if (parser->local.usage_index >= HID_MAX_USAGES) {
-               dbg("usage index exceeded");
+               dbg_hid("usage index exceeded\n");
                return -1;
        }
        parser->local.usage[parser->local.usage_index] = usage;
@@ -202,12 +211,12 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        int i;
 
        if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
-               dbg("hid_register_report failed");
+               dbg_hid("hid_register_report failed\n");
                return -1;
        }
 
        if (parser->global.logical_maximum < parser->global.logical_minimum) {
-               dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+               dbg_hid("logical range invalid %d %d\n", parser->global.logical_minimum, parser->global.logical_maximum);
                return -1;
        }
 
@@ -287,7 +296,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                case HID_GLOBAL_ITEM_TAG_PUSH:
 
                        if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-                               dbg("global enviroment stack overflow");
+                               dbg_hid("global enviroment stack overflow\n");
                                return -1;
                        }
 
@@ -298,7 +307,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                case HID_GLOBAL_ITEM_TAG_POP:
 
                        if (!parser->global_stack_ptr) {
-                               dbg("global enviroment stack underflow");
+                               dbg_hid("global enviroment stack underflow\n");
                                return -1;
                        }
 
@@ -342,27 +351,27 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 
                case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
                        if ((parser->global.report_size = item_udata(item)) > 32) {
-                               dbg("invalid report_size %d", parser->global.report_size);
+                               dbg_hid("invalid report_size %d\n", parser->global.report_size);
                                return -1;
                        }
                        return 0;
 
                case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
                        if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-                               dbg("invalid report_count %d", parser->global.report_count);
+                               dbg_hid("invalid report_count %d\n", parser->global.report_count);
                                return -1;
                        }
                        return 0;
 
                case HID_GLOBAL_ITEM_TAG_REPORT_ID:
                        if ((parser->global.report_id = item_udata(item)) == 0) {
-                               dbg("report_id 0 is invalid");
+                               dbg_hid("report_id 0 is invalid\n");
                                return -1;
                        }
                        return 0;
 
                default:
-                       dbg("unknown global tag 0x%x", item->tag);
+                       dbg_hid("unknown global tag 0x%x\n", item->tag);
                        return -1;
        }
 }
@@ -377,7 +386,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        unsigned n;
 
        if (item->size == 0) {
-               dbg("item data expected for local item");
+               dbg_hid("item data expected for local item\n");
                return -1;
        }
 
@@ -395,14 +404,14 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                                 * items and the first delimiter set.
                                 */
                                if (parser->local.delimiter_depth != 0) {
-                                       dbg("nested delimiters");
+                                       dbg_hid("nested delimiters\n");
                                        return -1;
                                }
                                parser->local.delimiter_depth++;
                                parser->local.delimiter_branch++;
                        } else {
                                if (parser->local.delimiter_depth < 1) {
-                                       dbg("bogus close delimiter");
+                                       dbg_hid("bogus close delimiter\n");
                                        return -1;
                                }
                                parser->local.delimiter_depth--;
@@ -412,7 +421,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -424,7 +433,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -437,7 +446,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -446,14 +455,14 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
 
                        for (n = parser->local.usage_minimum; n <= data; n++)
                                if (hid_add_usage(parser, n)) {
-                                       dbg("hid_add_usage failed\n");
+                                       dbg_hid("hid_add_usage failed\n");
                                        return -1;
                                }
                        return 0;
 
                default:
 
-                       dbg("unknown local item tag 0x%x", item->tag);
+                       dbg_hid("unknown local item tag 0x%x\n", item->tag);
                        return 0;
        }
        return 0;
@@ -487,7 +496,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
                        ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
                        break;
                default:
-                       dbg("unknown main item tag 0x%x", item->tag);
+                       dbg_hid("unknown main item tag 0x%x\n", item->tag);
                        ret = 0;
        }
 
@@ -502,7 +511,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
 
 static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
 {
-       dbg("reserved item type, tag 0x%x", item->tag);
+       dbg_hid("reserved item type, tag 0x%x\n", item->tag);
        return 0;
 }
 
@@ -667,14 +676,14 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
        while ((start = fetch_item(start, end, &item)) != NULL) {
 
                if (item.format != HID_ITEM_FORMAT_SHORT) {
-                       dbg("unexpected long global item");
+                       dbg_hid("unexpected long global item\n");
                        hid_free_device(device);
                        vfree(parser);
                        return NULL;
                }
 
                if (dispatch_type[item.type](parser, &item)) {
-                       dbg("item %u %u %u %u parsing failed\n",
+                       dbg_hid("item %u %u %u %u parsing failed\n",
                                item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
                        hid_free_device(device);
                        vfree(parser);
@@ -683,13 +692,13 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 
                if (start == end) {
                        if (parser->collection_stack_ptr) {
-                               dbg("unbalanced collection at end of report description");
+                               dbg_hid("unbalanced collection at end of report description\n");
                                hid_free_device(device);
                                vfree(parser);
                                return NULL;
                        }
                        if (parser->local.delimiter_depth) {
-                               dbg("unbalanced delimiter at end of report description");
+                               dbg_hid("unbalanced delimiter at end of report description\n");
                                hid_free_device(device);
                                vfree(parser);
                                return NULL;
@@ -699,7 +708,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
                }
        }
 
-       dbg("item fetching failed at offset %d\n", (int)(end - start));
+       dbg_hid("item fetching failed at offset %d\n", (int)(end - start));
        hid_free_device(device);
        vfree(parser);
        return NULL;
@@ -750,7 +759,9 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 {
        u64 x;
 
-       WARN_ON(n > 32);
+       if (n > 32)
+               printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
+                               n, current->comm);
 
        report += offset >> 3;  /* adjust byte index */
        offset &= 7;            /* now only need bit offset into one byte */
@@ -772,8 +783,13 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
        __le64 x;
        u64 m = (1ULL << n) - 1;
 
-       WARN_ON(n > 32);
+       if (n > 32)
+               printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
+                               n, current->comm);
 
+       if (value > m)
+               printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
+                               value, current->comm);
        WARN_ON(value > m);
        value &= m;
 
@@ -915,13 +931,13 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
        hid_dump_input(field->usage + offset, value);
 
        if (offset >= field->report_count) {
-               dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+               dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count);
                hid_dump_field(field, 8);
                return -1;
        }
        if (field->logical_minimum < 0) {
                if (value != snto32(s32ton(value, size), size)) {
-                       dbg("value %d is out of range", value);
+                       dbg_hid("value %d is out of range\n", value);
                        return -1;
                }
        }
@@ -934,19 +950,17 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 {
        struct hid_report_enum *report_enum = hid->report_enum + type;
        struct hid_report *report;
-       int n, rsize;
+       int n, rsize, i;
 
        if (!hid)
                return -ENODEV;
 
        if (!size) {
-               dbg("empty report");
+               dbg_hid("empty report\n");
                return -1;
        }
 
-#ifdef CONFIG_HID_DEBUG
-       printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
-#endif
+       dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
 
        n = 0;                          /* Normally report number is 0 */
        if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
@@ -954,30 +968,28 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
                size--;
        }
 
-#ifdef CONFIG_HID_DEBUG
-       {
-               int i;
-               printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
-               for (i = 0; i < size; i++)
-                       printk(" %02x", data[i]);
-               printk("\n");
-       }
-#endif
+       /* dump the report descriptor */
+       dbg_hid("report %d (size %u) = ", n, size);
+       for (i = 0; i < size; i++)
+               dbg_hid_line(" %02x", data[i]);
+       dbg_hid_line("\n");
 
        if (!(report = report_enum->report_id_hash[n])) {
-               dbg("undefined report_id %d received", n);
+               dbg_hid("undefined report_id %d received\n", n);
                return -1;
        }
 
        rsize = ((report->size - 1) >> 3) + 1;
 
        if (size < rsize) {
-               dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
+               dbg_hid("report %d is too short, (%d < %d)\n", 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);
 
        for (n = 0; n < report->maxfield; n++)
                hid_input_field(hid, report->field[n], data, interrupt);
@@ -989,5 +1001,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 }
 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);