diff options
| -rw-r--r-- | drivers/hid/hidraw.c | 1 | ||||
| -rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 87 | ||||
| -rw-r--r-- | drivers/hid/uhid.c | 95 |
3 files changed, 174 insertions, 9 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 413a73187d33..f3bbbce8353b 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
| @@ -581,6 +581,7 @@ int __init hidraw_init(void) | |||
| 581 | if (result < 0) | 581 | if (result < 0) |
| 582 | goto error_class; | 582 | goto error_class; |
| 583 | 583 | ||
| 584 | printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n"); | ||
| 584 | out: | 585 | out: |
| 585 | return result; | 586 | return result; |
| 586 | 587 | ||
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index e766b5614ef5..ec7930217a6d 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
| 35 | #include <linux/hid.h> | 35 | #include <linux/hid.h> |
| 36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
| 37 | #include <linux/acpi.h> | ||
| 37 | 38 | ||
| 38 | #include <linux/i2c/i2c-hid.h> | 39 | #include <linux/i2c/i2c-hid.h> |
| 39 | 40 | ||
| @@ -139,6 +140,8 @@ struct i2c_hid { | |||
| 139 | unsigned long flags; /* device flags */ | 140 | unsigned long flags; /* device flags */ |
| 140 | 141 | ||
| 141 | wait_queue_head_t wait; /* For waiting the interrupt */ | 142 | wait_queue_head_t wait; /* For waiting the interrupt */ |
| 143 | |||
| 144 | struct i2c_hid_platform_data pdata; | ||
| 142 | }; | 145 | }; |
| 143 | 146 | ||
| 144 | static int __i2c_hid_command(struct i2c_client *client, | 147 | static int __i2c_hid_command(struct i2c_client *client, |
| @@ -821,6 +824,70 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) | |||
| 821 | return 0; | 824 | return 0; |
| 822 | } | 825 | } |
| 823 | 826 | ||
| 827 | #ifdef CONFIG_ACPI | ||
| 828 | static int i2c_hid_acpi_pdata(struct i2c_client *client, | ||
| 829 | struct i2c_hid_platform_data *pdata) | ||
| 830 | { | ||
| 831 | static u8 i2c_hid_guid[] = { | ||
| 832 | 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, | ||
| 833 | 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, | ||
| 834 | }; | ||
| 835 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 836 | union acpi_object params[4], *obj; | ||
| 837 | struct acpi_object_list input; | ||
| 838 | struct acpi_device *adev; | ||
| 839 | acpi_handle handle; | ||
| 840 | |||
| 841 | handle = ACPI_HANDLE(&client->dev); | ||
| 842 | if (!handle || acpi_bus_get_device(handle, &adev)) | ||
| 843 | return -ENODEV; | ||
| 844 | |||
| 845 | input.count = ARRAY_SIZE(params); | ||
| 846 | input.pointer = params; | ||
| 847 | |||
| 848 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 849 | params[0].buffer.length = sizeof(i2c_hid_guid); | ||
| 850 | params[0].buffer.pointer = i2c_hid_guid; | ||
| 851 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 852 | params[1].integer.value = 1; | ||
| 853 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 854 | params[2].integer.value = 1; /* HID function */ | ||
| 855 | params[3].type = ACPI_TYPE_INTEGER; | ||
| 856 | params[3].integer.value = 0; | ||
| 857 | |||
| 858 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) { | ||
| 859 | dev_err(&client->dev, "device _DSM execution failed\n"); | ||
| 860 | return -ENODEV; | ||
| 861 | } | ||
| 862 | |||
| 863 | obj = (union acpi_object *)buf.pointer; | ||
| 864 | if (obj->type != ACPI_TYPE_INTEGER) { | ||
| 865 | dev_err(&client->dev, "device _DSM returned invalid type: %d\n", | ||
| 866 | obj->type); | ||
| 867 | kfree(buf.pointer); | ||
| 868 | return -EINVAL; | ||
| 869 | } | ||
| 870 | |||
| 871 | pdata->hid_descriptor_address = obj->integer.value; | ||
| 872 | |||
| 873 | kfree(buf.pointer); | ||
| 874 | return 0; | ||
| 875 | } | ||
| 876 | |||
| 877 | static const struct acpi_device_id i2c_hid_acpi_match[] = { | ||
| 878 | {"ACPI0C50", 0 }, | ||
| 879 | {"PNP0C50", 0 }, | ||
| 880 | { }, | ||
| 881 | }; | ||
| 882 | MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); | ||
| 883 | #else | ||
| 884 | static inline int i2c_hid_acpi_pdata(struct i2c_client *client, | ||
| 885 | struct i2c_hid_platform_data *pdata) | ||
| 886 | { | ||
| 887 | return -ENODEV; | ||
| 888 | } | ||
| 889 | #endif | ||
| 890 | |||
| 824 | static int i2c_hid_probe(struct i2c_client *client, | 891 | static int i2c_hid_probe(struct i2c_client *client, |
| 825 | const struct i2c_device_id *dev_id) | 892 | const struct i2c_device_id *dev_id) |
| 826 | { | 893 | { |
| @@ -832,11 +899,6 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
| 832 | 899 | ||
| 833 | dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); | 900 | dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); |
| 834 | 901 | ||
| 835 | if (!platform_data) { | ||
| 836 | dev_err(&client->dev, "HID register address not provided\n"); | ||
| 837 | return -EINVAL; | ||
| 838 | } | ||
| 839 | |||
| 840 | if (!client->irq) { | 902 | if (!client->irq) { |
| 841 | dev_err(&client->dev, | 903 | dev_err(&client->dev, |
| 842 | "HID over i2c has not been provided an Int IRQ\n"); | 904 | "HID over i2c has not been provided an Int IRQ\n"); |
| @@ -847,11 +909,22 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
| 847 | if (!ihid) | 909 | if (!ihid) |
| 848 | return -ENOMEM; | 910 | return -ENOMEM; |
| 849 | 911 | ||
| 912 | if (!platform_data) { | ||
| 913 | ret = i2c_hid_acpi_pdata(client, &ihid->pdata); | ||
| 914 | if (ret) { | ||
| 915 | dev_err(&client->dev, | ||
| 916 | "HID register address not provided\n"); | ||
| 917 | goto err; | ||
| 918 | } | ||
| 919 | } else { | ||
| 920 | ihid->pdata = *platform_data; | ||
| 921 | } | ||
| 922 | |||
| 850 | i2c_set_clientdata(client, ihid); | 923 | i2c_set_clientdata(client, ihid); |
| 851 | 924 | ||
| 852 | ihid->client = client; | 925 | ihid->client = client; |
| 853 | 926 | ||
| 854 | hidRegister = platform_data->hid_descriptor_address; | 927 | hidRegister = ihid->pdata.hid_descriptor_address; |
| 855 | ihid->wHIDDescRegister = cpu_to_le16(hidRegister); | 928 | ihid->wHIDDescRegister = cpu_to_le16(hidRegister); |
| 856 | 929 | ||
| 857 | init_waitqueue_head(&ihid->wait); | 930 | init_waitqueue_head(&ihid->wait); |
| @@ -884,6 +957,7 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
| 884 | hid->hid_get_raw_report = i2c_hid_get_raw_report; | 957 | hid->hid_get_raw_report = i2c_hid_get_raw_report; |
| 885 | hid->hid_output_raw_report = i2c_hid_output_raw_report; | 958 | hid->hid_output_raw_report = i2c_hid_output_raw_report; |
| 886 | hid->dev.parent = &client->dev; | 959 | hid->dev.parent = &client->dev; |
| 960 | ACPI_HANDLE_SET(&hid->dev, ACPI_HANDLE(&client->dev)); | ||
| 887 | hid->bus = BUS_I2C; | 961 | hid->bus = BUS_I2C; |
| 888 | hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); | 962 | hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); |
| 889 | hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); | 963 | hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); |
| @@ -975,6 +1049,7 @@ static struct i2c_driver i2c_hid_driver = { | |||
| 975 | .name = "i2c_hid", | 1049 | .name = "i2c_hid", |
| 976 | .owner = THIS_MODULE, | 1050 | .owner = THIS_MODULE, |
| 977 | .pm = &i2c_hid_pm, | 1051 | .pm = &i2c_hid_pm, |
| 1052 | .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), | ||
| 978 | }, | 1053 | }, |
| 979 | 1054 | ||
| 980 | .probe = i2c_hid_probe, | 1055 | .probe = i2c_hid_probe, |
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 714cd8cc9579..fc307e0422af 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/atomic.h> | 13 | #include <linux/atomic.h> |
| 14 | #include <linux/compat.h> | ||
| 14 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 15 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
| 16 | #include <linux/hid.h> | 17 | #include <linux/hid.h> |
| @@ -276,6 +277,94 @@ static struct hid_ll_driver uhid_hid_driver = { | |||
| 276 | .parse = uhid_hid_parse, | 277 | .parse = uhid_hid_parse, |
| 277 | }; | 278 | }; |
| 278 | 279 | ||
| 280 | #ifdef CONFIG_COMPAT | ||
| 281 | |||
| 282 | /* Apparently we haven't stepped on these rakes enough times yet. */ | ||
| 283 | struct uhid_create_req_compat { | ||
| 284 | __u8 name[128]; | ||
| 285 | __u8 phys[64]; | ||
| 286 | __u8 uniq[64]; | ||
| 287 | |||
| 288 | compat_uptr_t rd_data; | ||
| 289 | __u16 rd_size; | ||
| 290 | |||
| 291 | __u16 bus; | ||
| 292 | __u32 vendor; | ||
| 293 | __u32 product; | ||
| 294 | __u32 version; | ||
| 295 | __u32 country; | ||
| 296 | } __attribute__((__packed__)); | ||
| 297 | |||
| 298 | static int uhid_event_from_user(const char __user *buffer, size_t len, | ||
| 299 | struct uhid_event *event) | ||
| 300 | { | ||
| 301 | if (is_compat_task()) { | ||
| 302 | u32 type; | ||
| 303 | |||
| 304 | if (get_user(type, buffer)) | ||
| 305 | return -EFAULT; | ||
| 306 | |||
| 307 | if (type == UHID_CREATE) { | ||
| 308 | /* | ||
| 309 | * This is our messed up request with compat pointer. | ||
| 310 | * It is largish (more than 256 bytes) so we better | ||
| 311 | * allocate it from the heap. | ||
| 312 | */ | ||
| 313 | struct uhid_create_req_compat *compat; | ||
| 314 | |||
| 315 | compat = kmalloc(sizeof(*compat), GFP_KERNEL); | ||
| 316 | if (!compat) | ||
| 317 | return -ENOMEM; | ||
| 318 | |||
| 319 | buffer += sizeof(type); | ||
| 320 | len -= sizeof(type); | ||
| 321 | if (copy_from_user(compat, buffer, | ||
| 322 | min(len, sizeof(*compat)))) { | ||
| 323 | kfree(compat); | ||
| 324 | return -EFAULT; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* Shuffle the data over to proper structure */ | ||
| 328 | event->type = type; | ||
| 329 | |||
| 330 | memcpy(event->u.create.name, compat->name, | ||
| 331 | sizeof(compat->name)); | ||
| 332 | memcpy(event->u.create.phys, compat->phys, | ||
| 333 | sizeof(compat->phys)); | ||
| 334 | memcpy(event->u.create.uniq, compat->uniq, | ||
| 335 | sizeof(compat->uniq)); | ||
| 336 | |||
| 337 | event->u.create.rd_data = compat_ptr(compat->rd_data); | ||
| 338 | event->u.create.rd_size = compat->rd_size; | ||
| 339 | |||
| 340 | event->u.create.bus = compat->bus; | ||
| 341 | event->u.create.vendor = compat->vendor; | ||
| 342 | event->u.create.product = compat->product; | ||
| 343 | event->u.create.version = compat->version; | ||
| 344 | event->u.create.country = compat->country; | ||
| 345 | |||
| 346 | kfree(compat); | ||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | /* All others can be copied directly */ | ||
| 350 | } | ||
| 351 | |||
| 352 | if (copy_from_user(event, buffer, min(len, sizeof(*event)))) | ||
| 353 | return -EFAULT; | ||
| 354 | |||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | #else | ||
| 358 | static int uhid_event_from_user(const char __user *buffer, size_t len, | ||
| 359 | struct uhid_event *event) | ||
| 360 | { | ||
| 361 | if (copy_from_user(event, buffer, min(len, sizeof(*event)))) | ||
| 362 | return -EFAULT; | ||
| 363 | |||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | #endif | ||
| 367 | |||
| 279 | static int uhid_dev_create(struct uhid_device *uhid, | 368 | static int uhid_dev_create(struct uhid_device *uhid, |
| 280 | const struct uhid_event *ev) | 369 | const struct uhid_event *ev) |
| 281 | { | 370 | { |
| @@ -498,10 +587,10 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, | |||
| 498 | 587 | ||
| 499 | memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); | 588 | memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); |
| 500 | len = min(count, sizeof(uhid->input_buf)); | 589 | len = min(count, sizeof(uhid->input_buf)); |
| 501 | if (copy_from_user(&uhid->input_buf, buffer, len)) { | 590 | |
| 502 | ret = -EFAULT; | 591 | ret = uhid_event_from_user(buffer, len, &uhid->input_buf); |
| 592 | if (ret) | ||
| 503 | goto unlock; | 593 | goto unlock; |
| 504 | } | ||
| 505 | 594 | ||
| 506 | switch (uhid->input_buf.type) { | 595 | switch (uhid->input_buf.type) { |
| 507 | case UHID_CREATE: | 596 | case UHID_CREATE: |
